Merge inbound to central
authorWes Kocher <wkocher@mozilla.com>
Wed, 19 Jun 2013 16:37:58 -0700
changeset 147151 8ea92aeab78353889f6928cb24d87f7330cd8c74
parent 147101 ca07be78813b38465a78eda64da0961c4c96fdf5 (current diff)
parent 147150 32bffdedafeeeb1dfbe3d8824c4cf9e55d81fa42 (diff)
child 147216 34a280cae36826f84110f8d5177f2e027ab65b28
child 147253 f5a90edfa8f62ebb226c1408752c59f4faab16fa
child 147284 148f8183bf89577fbecab72da8ca29f5a9ce01dd
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone24.0a1
first release with
nightly linux32
8ea92aeab783 / 24.0a1 / 20130620031010 / files
nightly linux64
8ea92aeab783 / 24.0a1 / 20130620031010 / files
nightly mac
8ea92aeab783 / 24.0a1 / 20130620031010 / files
nightly win32
8ea92aeab783 / 24.0a1 / 20130620031010 / files
nightly win64
8ea92aeab783 / 24.0a1 / 20130620031010 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to central
content/html/content/src/nsHTMLFormElement.cpp
content/html/content/src/nsHTMLFormElement.h
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -107,17 +107,17 @@ SocialUI = {
         case "social:ambient-notification-changed":
           if (this._matchesCurrentProvider(data)) {
             SocialToolbar.updateButton();
             SocialMenu.populate();
           }
           break;
         case "social:profile-changed":
           if (this._matchesCurrentProvider(data)) {
-            SocialToolbar.updateProfile();
+            SocialToolbar.updateProvider();
             SocialMark.update();
             SocialChatBar.update();
           }
           break;
         case "social:page-mark-config":
           if (this._matchesCurrentProvider(data)) {
             SocialMark.updateMarkState();
           }
@@ -1068,17 +1068,16 @@ SocialToolbar = {
       userDetailsBroadcaster.removeAttribute("src");
       userDetailsBroadcaster.removeAttribute("image");
     }
 
     userDetailsBroadcaster.setAttribute("value", loggedInStatusValue);
     userDetailsBroadcaster.setAttribute("label", loggedInStatusValue);
   },
 
-  // XXX doesn't this need to be called for profile changes, given its use of provider.profile?
   updateButton: function SocialToolbar_updateButton() {
     this._updateButtonHiddenState();
     let panel = document.getElementById("social-notification-panel");
     panel.hidden = !SocialUI.enabled;
 
     let command = document.getElementById("Social:ToggleNotifications");
     command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
 
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -54,31 +54,31 @@ endif
 #
 # browser_sanitizeDialog_treeView.js is disabled until the tree view is added
 # back to the clear recent history dialog (sanitize.xul), if it ever is (bug
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
+# browser_bug386835.js is disabled for intermittent failures (bug 880226)
 
 _BROWSER_FILES = \
                  head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_keywordSearch_postData.js \
                  POSTSearchEngine.xml \
                  print_postdata.sjs \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
                  browser_bug329212.js \
                  browser_bug356571.js \
                  browser_bug380960.js \
-                 browser_bug386835.js \
                  browser_bug405137.js \
                  browser_bug406216.js \
                  browser_bug409481.js \
                  browser_bug409624.js \
                  browser_bug413915.js \
                  browser_bug416661.js \
                  browser_bug417483.js \
                  browser_bug419612.js \
--- a/browser/base/content/test/browser_CTP_drag_drop.js
+++ b/browser/base/content/test/browser_CTP_drag_drop.js
@@ -127,17 +127,20 @@ function part11() {
   // we have to actually show the panel to get the bindings to instantiate
   notification.options.eventCallback = part12;
   // this scripts the plugin, triggering the popup notification
   try {
     gNewWindow.gBrowser.selectedBrowser.contentDocument.getElementById("test").wrappedJSObject.getObjectValue();
   } catch (e) {}
 }
 
-function part12() {
+function part12(type) {
+  if (type != "shown") {
+    return;
+  }
   let notification = PopupNotifications.getNotification("click-to-play-plugins", gNewWindow.gBrowser.selectedBrowser);
   notification.options.eventCallback = null;
   let centerAction = null;
   for (let action of notification.options.centerActions) {
     if (action.message == "Test") {
       centerAction = action;
       break;
     }
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -713,16 +713,19 @@ function test18e() {
 function test18f() {
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(notification, "Test 18f, Should have a click-to-play notification");
   ok(notification.dismissed, "Test 18f, notification should start dismissed");
   var plugin = gTestBrowser.contentDocument.getElementById("test");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(!objLoadingContent.activated, "Test 18f, Plugin should not be activated");
 
+  // XXXBAD: this code doesn't do what you think it does! it is actually
+  // observing the "removed" event of the old notification, since we create
+  // a *new* one when the plugin is clicked.
   notification.options.eventCallback = function() { executeSoon(test18g); };
   EventUtils.synthesizeMouseAtCenter(plugin, {}, gTestBrowser.contentWindow);
 }
 
 function test18g() {
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(notification, "Test 18g, Should have a click-to-play notification");
   ok(!notification.dismissed, "Test 18g, notification should be open");
@@ -874,17 +877,20 @@ function test21a() {
     ok(!objLoadingContent.activated, "Test 21a, Plugin with id=" + plugin.id + " should not be activated");
   }
 
   // we have to actually show the panel to get the bindings to instantiate
   notification.options.eventCallback = test21b;
   notification.reshow();
 }
 
-function test21b() {
+function test21b(type) {
+  if (type != "shown") {
+    return;
+  }
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   notification.options.eventCallback = null;
   var centerAction = null;
   for (var action of notification.options.centerActions) {
     if (action.message == "Test") {
       centerAction = action;
       break;
     }
@@ -933,17 +939,20 @@ function test21c() {
     ok(!objLoadingContent.activated, "Test 21c, Plugin with id=" + plugin.id + " should not be activated");
   }
 
   // we have to actually show the panel to get the bindings to instantiate
   notification.options.eventCallback = test21d;
   notification.reshow();
 }
 
-function test21d() {
+function test21d(type) {
+  if (type != "shown") {
+    return;
+  }
   var notification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   notification.options.eventCallback = null;
 
   var centerAction = null;
   for (var action of notification.options.centerActions) {
     if (action.message == "Second Test") {
       centerAction = action;
       break;
--- a/browser/base/content/test/browser_plugins_added_dynamically.js
+++ b/browser/base/content/test/browser_plugins_added_dynamically.js
@@ -106,17 +106,20 @@ function testActivateAddSameTypePart2() 
   let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(popupNotification, "testActivateAddSameTypePart2: should have a click-to-play notification");
 
   // we have to actually show the panel to get the bindings to instantiate
   popupNotification.options.eventCallback = testActivateAddSameTypePart3;
   popupNotification.reshow();
 }
 
-function testActivateAddSameTypePart3() {
+function testActivateAddSameTypePart3(type) {
+  if (type != "shown") {
+    return;
+  }
   let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   popupNotification.options.eventCallback = null;
   let centerAction = null;
   for (let action of popupNotification.options.centerActions) {
     if (action.message == "Test") {
       centerAction = action;
       break;
     }
@@ -184,17 +187,20 @@ function testActivateAddDifferentTypePar
   let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   ok(popupNotification, "testActivateAddDifferentTypePart2: should have a click-to-play notification");
 
   // we have to actually show the panel to get the bindings to instantiate
   popupNotification.options.eventCallback = testActivateAddDifferentTypePart3;
   popupNotification.reshow();
 }
 
-function testActivateAddDifferentTypePart3() {
+function testActivateAddDifferentTypePart3(type) {
+  if (type != "shown") {
+    return;
+  }
   let popupNotification = PopupNotifications.getNotification("click-to-play-plugins", gTestBrowser);
   popupNotification.options.eventCallback = null;
   let centerAction = null;
   for (let action of popupNotification.options.centerActions) {
     if (action.message == "Test") {
       centerAction = action;
       break;
     }
--- a/browser/base/content/test/browser_popupNotification.js
+++ b/browser/base/content/test/browser_popupNotification.js
@@ -132,16 +132,19 @@ function basicNotification() {
     }
   ];
   this.options = {
     eventCallback: function (eventName) {
       switch (eventName) {
         case "dismissed":
           self.dismissalCallbackTriggered = true;
           break;
+        case "showing":
+          self.showingCallbackTriggered = true;
+          break;
         case "shown":
           self.shownCallbackTriggered = true;
           break;
         case "removed":
           self.removedCallbackTriggered = true;
           break;
       }
     }
@@ -853,32 +856,54 @@ var tests = [
          "notification2 anchor should be visible");
 
       dismissNotification(popup);
     },
     onHidden: function(popup) {
       this.notification1.remove();
       this.notification2.remove();
     }
+  },
+  { // Test #30 - Showing should be able to modify the popup data
+    run: function() {
+      this.notifyObj = new basicNotification();
+      var normalCallback = this.notifyObj.options.eventCallback;
+      this.notifyObj.options.eventCallback = function (eventName) {
+        if (eventName == "showing") {
+          this.mainAction.label = "Alternate Label";
+        }
+        normalCallback.call(this, eventName);
+      };
+      showNotification(this.notifyObj);
+    },
+    onShown: function(popup) {
+      // checkPopup checks for the matching label. Note that this assumes that
+      // this.notifyObj.mainAction is the same as notification.mainAction,
+      // which could be a problem if we ever decided to deep-copy.
+      checkPopup(popup, this.notifyObj);
+      triggerMainCommand(popup);
+    },
+    onHidden: function() { }
   }
 ];
 
 function showNotification(notifyObj) {
   return PopupNotifications.show(notifyObj.browser,
                                  notifyObj.id,
                                  notifyObj.message,
                                  notifyObj.anchorID,
                                  notifyObj.mainAction,
                                  notifyObj.secondaryActions,
                                  notifyObj.options);
 }
 
 function checkPopup(popup, notificationObj) {
   info("[Test #" + gTestIndex + "] checking popup");
 
+  ok(notificationObj.showingCallbackTriggered, "showing callback was triggered");
   ok(notificationObj.shownCallbackTriggered, "shown callback was triggered");
 
   let notifications = popup.childNodes;
   is(notifications.length, 1, "one notification displayed");
   let notification = notifications[0];
   if (!notification)
     return;
   let icon = document.getAnonymousElementByAttribute(notification, "class", "popup-notification-icon");
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -110,18 +110,18 @@ function getTestPlugin(aName) {
   ok(false, "Unable to find plugin");
   return null;
 }
 
 function updateBlocklist(aCallback) {
   var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
                           .getService(Ci.nsITimerCallback);
   var observer = function() {
-    aCallback();
     Services.obs.removeObserver(observer, "blocklist-updated");
+    SimpleTest.executeSoon(aCallback);
   };
   Services.obs.addObserver(observer, "blocklist-updated", false);
   blocklistNotifier.notify(null);
 }
 
 var _originalTestBlocklistURL = null;
 function setAndUpdateBlocklist(aURL, aCallback) {
   if (!_originalTestBlocklistURL)
--- a/browser/base/content/test/social/browser_social_toolbar.js
+++ b/browser/base/content/test/social/browser_social_toolbar.js
@@ -1,21 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+let manifest = { // normal provider
+  name: "provider 1",
+  origin: "https://example.com",
+  workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
+  iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
+};
+
 function test() {
   waitForExplicitFinish();
 
-  let manifest = { // normal provider
-    name: "provider 1",
-    origin: "https://example.com",
-    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
-    iconURL: "https://example.com/browser/browser/base/content/test/moz.png"
-  };
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, finishcb);
   });
 }
 
 var tests = {
   testProfileNone: function(next, useNull) {
     let profile = useNull ? null : {};
@@ -30,24 +31,29 @@ var tests = {
     ok(!userButton.hidden, "username is visible");
     is(userButton.getAttribute("label"), notLoggedInStatusValue, "label reflects not being logged in");
     next();
   },
   testProfileNull: function(next) {
     this.testProfileNone(next, true);
   },
   testProfileSet: function(next) {
+    let statusIcon = document.getElementById("social-provider-button").style.listStyleImage;
+    is(statusIcon, "url(\"" + manifest.iconURL + "\")", "manifest iconURL is showing");
     let profile = {
       portrait: "https://example.com/portrait.jpg",
       userName: "trickster",
       displayName: "Kuma Lisa",
-      profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
+      profileURL: "http://example.com/Kuma_Lisa",
+      iconURL: "https://example.com/browser/browser/base/content/test/social/moz.png"
     }
     Social.provider.updateUserProfile(profile);
     // check dom values
+    statusIcon = document.getElementById("social-provider-button").style.listStyleImage;
+    is(statusIcon, "url(\"" + profile.iconURL + "\")", "profile iconURL is showing");
     let portrait = document.getElementsByClassName("social-statusarea-user-portrait")[0].getAttribute("src");
     is(profile.portrait, portrait, "portrait is set");
     let userButton = document.getElementsByClassName("social-statusarea-loggedInStatus")[0];
     ok(!userButton.hidden, "username is visible");
     is(userButton.value, profile.userName, "username is set");
     next();
   },
   testNoAmbientNotificationsIsNoKeyboardMenu: function(next) {
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..769c636340e11f9d2a0b7eb6a84d574dd9563f0c
GIT binary patch
literal 580
zc$@)50=xZ*P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz)=5M`RCwBA
z{Qv(y10?_;fS8au@87>?@9gaSt*os4-<6T^zln*-e<1(Y>eZ{a-@A8D7MlS80mJ}u
z0SKQtbH>fs*!aH-1H=C_K)ecw?*efe5W7I}s#U9Y!PLVrKmdV>nKNfT1{(H16si$K
zmjm&CV+al6D=8`c7X*o+82}JK4A3z64>JJB_`e(E3S)?2<zN>X{|^lf1sei(+1<Me
zFarPr2&}oIqvIC?)OL^o?-&p^!wh-{#k-;2f_VoZfS{%bLi}zFF<>UtAY{W<LBj?n
zz6$CsfB=HI;P*^44eyZn#$YcBg1rF~2L~`P&;bI75#$0;v@zVf$It;Z4d`qJS0Dzu
zh@l)BQx!mb7Roj*FK2kaXAgtR*|Q9LfP8=e0=od{pY0$UI-sVXf!f>w#jt?wfcn3@
zy!=0d5|Evi_8%aC7~Z{m#}1AKK|~<_M{=g1px}QcP=ErR57Iaj7$e5OumVLr$n^jL
z1djz!sJcLHd57c@W2lWFi_p^m2m=HVoB>kgf@C|$pqa*ykjAAMgaHBwo)>`0c=vmt
z+g3yQpuk*x7A(#H^u|wInF%0(FiZq_r2`t3pnwGh6fWCA7$ATcDb3CR0R{jJCzQv)
SYsoAC0000<MNUMnLSTYrIq9PS
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -10,16 +10,17 @@ relativesrcdir  = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # browser_506482.js is disabled because of frequent failures (bug 538672)
 # browser_526613.js is disabled because of frequent failures (bug 534489)
 # browser_589246.js is disabled for leaking browser windows (bug 752467)
 # browser_580512.js is disabled for leaking browser windows (bug 752467)
 # browser_capabilities.js is disabled for using resources outside of the build network (bug 882575)
+# browser_707862.js & browser_705597.js are disabled whilst waiting for review (bug 861700 & bug 883592)
 
 MOCHITEST_BROWSER_FILES = \
 	head.js \
 	browser_attributes.js \
 	browser_dying_cache.js \
 	browser_form_restore_events.js \
 	browser_form_restore_events_sample.html \
 	browser_formdata_format.js \
@@ -127,18 +128,16 @@ MOCHITEST_BROWSER_FILES = \
 	browser_662743_sample.html \
 	browser_662812.js \
 	browser_665702-state_session.js \
 	browser_682507.js \
 	browser_687710.js \
 	browser_687710_2.js \
 	browser_694378.js \
 	browser_701377.js \
-	browser_705597.js \
-	browser_707862.js \
 	browser_739531.js \
 	browser_739531_sample.html \
 	browser_739805.js \
 	browser_819510_perwindowpb.js \
 	browser_833286_atomic_backup.js \
 	$(filter disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html) \
 	$(filter disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html) \
 	$(filter disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html) \
--- a/build/mobile/robocop/Makefile.in
+++ b/build/mobile/robocop/Makefile.in
@@ -8,18 +8,16 @@ srcdir      = @srcdir@
 VPATH       = @srcdir@
 
 mobile-tests := mobile/android/base/tests
 TESTPATH     := $(topsrcdir)/$(mobile-tests)
 dir-tests    := $(DEPTH)/$(mobile-tests)
 
 include $(DEPTH)/config/autoconf.mk
 
-ANDROID_APK_NAME := robocop-debug
-
 ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.6.jar
 
 JAVAFILES = \
   R.java \
   $(NULL)
 
 RES_FILES = \
   res/values/strings.xml \
@@ -78,55 +76,49 @@ MOCHITEST_ROBOCOP_FILES := \
   $(wildcard $(TESTPATH)/*.xml) \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml \
   $(java-tests-dep) \
   $(_JAVA_HARNESS) \
   classes.dex \
-  $(ANDROID_APK_NAME).ap_ \
-  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
-  $(ANDROID_APK_NAME)-unaligned.apk \
-  $(ANDROID_APK_NAME).apk \
+  robocop.ap_ \
+  robocop-debug-signed.apk \
+  robocop-debug-signed-unaligned.apk \
   $(robocop-deps) \
   $(NULL)
 
 DEFINES += \
   -DANDROID_PACKAGE_NAME=$(ANDROID_PACKAGE_NAME) \
   $(NULL)
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(ROBOTIUM_PATH)
 
 include $(topsrcdir)/config/rules.mk
 
 # Override rules.mk java flags with the android specific ones
 include $(topsrcdir)/config/android-common.mk
 
 GENERATED_DIRS_tools = classes $(dir-tests)
 
-tools:: $(ANDROID_APK_NAME).apk
+libs:: robocop-debug-signed.apk
 
-classes.dex: $(ANDROID_APK_NAME).ap_
+classes.dex: robocop.ap_
 classes.dex: $(robocop-deps)
 classes.dex: $(java-harness-dep)
 classes.dex: $(java-tests-dep)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(java-tests-dep)
 	$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH) $(ANDROID_COMPT_LIB)
 
-$(ANDROID_APK_NAME).ap_: AndroidManifest.xml $(TESTPATH)/assets/*
+robocop.ap_: AndroidManifest.xml $(TESTPATH)/assets/*
 	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -I . -S res -A $(TESTPATH)/assets -F $@ -J ./
 
-$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
-	cp $< $@
-	$(ZIP) -v0 $@ classes.dex
+robocop-debug-signed-unaligned.apk: robocop.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
 
-$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
-	cp $< $@
-	$(DEBUG_JARSIGNER) $@
-
-$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $< $@
+robocop-debug-signed.apk: robocop-debug-signed-unaligned.apk
+	$(ZIPALIGN) -f -v 4 $^ $@
 
 # PP_java-tests not fully usable here
 # Intermediate step toward a library rule.
 $(dir-tests)/%.java: $(TESTPATH)/%.java.in $(call mkdir_deps,$(dir-tests))
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $< > $@
--- a/build/mobile/sutagent/android/Makefile.in
+++ b/build/mobile/sutagent/android/Makefile.in
@@ -4,18 +4,16 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-ANDROID_APK_NAME := sutAgentAndroid
-
 JAVAFILES = \
   AlertLooperThread.java \
   ASMozStub.java \
   CmdWorkerThread.java \
   DataWorkerThread.java \
   DoAlert.java \
   DoCommand.java \
   FindProcThread.java \
@@ -36,44 +34,45 @@ RES_FILES = \
   res/drawable/ic_stat_warning.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  $(ANDROID_APK_NAME).ap_ \
-  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
-  $(ANDROID_APK_NAME)-unaligned.apk \
-  $(ANDROID_APK_NAME).apk \
+  sutAgentAndroid.apk  \
+  sutAgentAndroid.ap_ \
+  sutAgentAndroid-unsigned-unaligned.apk \
+  sutAgentAndroid-unaligned.apk \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 EXTRA_JARS = $(srcdir)/network-libs/commons-net-2.0.jar:$(srcdir)/network-libs/jmdns.jar
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar:$(EXTRA_JARS)
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: $(ANDROID_APK_NAME).apk
+tools:: sutAgentAndroid.apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes $(subst :, ,$(EXTRA_JARS))
 
-$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
+sutAgentAndroid.ap_: $(srcdir)/AndroidManifest.xml
 	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
 
-$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
-	cp $< $@
-	$(ZIP) -v0 $@ classes.dex
+sutAgentAndroid-unsigned-unaligned.apk: sutAgentAndroid.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z sutAgentAndroid.ap_ -f classes.dex
 
-$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
+sutAgentAndroid-unaligned.apk: sutAgentAndroid-unsigned-unaligned.apk
 	cp $< $@
-	$(DEBUG_JARSIGNER) $@
+ifdef JARSIGNER
+	$(JARSIGNER) $@
+endif
 
-$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $< $@
+sutAgentAndroid.apk: sutAgentAndroid-unaligned.apk
+	$(ZIPALIGN) -f -v 4 sutAgentAndroid-unaligned.apk $@
--- a/build/mobile/sutagent/android/fencp/Makefile.in
+++ b/build/mobile/sutagent/android/fencp/Makefile.in
@@ -4,18 +4,16 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-ANDROID_APK_NAME := FenCP
-
 JAVAFILES = \
   DirCursor.java \
   FenCP.java \
   FenCPFP.java \
   FileCursor.java \
   R.java \
   $(NULL)
 
@@ -25,42 +23,40 @@ RES_FILES = \
   res/drawable-mdpi/icon.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  $(ANDROID_APK_NAME).ap_ \
-  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
-  $(ANDROID_APK_NAME)-unaligned.apk \
-  $(ANDROID_APK_NAME).apk \
+  FenCP.apk  \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: $(ANDROID_APK_NAME).apk
+tools:: FenCP.apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
-	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
+FenCP.ap_: $(srcdir)/AndroidManifest.xml
+	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
-$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
-	cp $< $@
-	$(ZIP) -v0 $@ classes.dex
+FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex
 
-$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
-	cp $< $@
-	$(DEBUG_JARSIGNER) $@
+FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk
+	cp  FenCP-unsigned-unaligned.apk $@
+ifdef JARSIGNER
+  $(JARSIGNER) $@
+endif
 
-$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $< $@
+FenCP.apk: FenCP-unaligned.apk
+	$(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
--- a/build/mobile/sutagent/android/ffxcp/Makefile.in
+++ b/build/mobile/sutagent/android/ffxcp/Makefile.in
@@ -4,18 +4,16 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-ANDROID_APK_NAME := FfxCP
-
 JAVAFILES = \
   DirCursor.java \
   ffxcp.java \
   FfxCPFP.java \
   FileCursor.java \
   R.java \
   $(NULL)
 
@@ -25,42 +23,40 @@ RES_FILES = \
   res/drawable-mdpi/icon.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  $(ANDROID_APK_NAME).ap_ \
-  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
-  $(ANDROID_APK_NAME)-unaligned.apk \
-  $(ANDROID_APK_NAME).apk \
+  FfxCP.apk  \
   $(NULL)
 
 GARBAGE_DIRS += network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: $(ANDROID_APK_NAME).apk
+tools:: FfxCP.apk
 
 classes.dex: $(JAVAFILES)
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
-	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
+FfxCP.ap_: $(srcdir)/AndroidManifest.xml
+	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
-$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
-	cp $< $@
-	$(ZIP) -v0 $@ classes.dex
+FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex
 
-$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
-	cp $< $@
-	$(DEBUG_JARSIGNER) $@
+FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk
+	cp  FfxCP-unsigned-unaligned.apk $@
+ifdef JARSIGNER
+  $(JARSIGNER) $@
+endif
 
-$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $< $@
+FfxCP.apk: FfxCP-unaligned.apk
+	$(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
--- a/build/mobile/sutagent/android/watcher/Makefile.in
+++ b/build/mobile/sutagent/android/watcher/Makefile.in
@@ -4,18 +4,16 @@
 
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
-ANDROID_APK_NAME := Watcher
-
 JAVAFILES = \
   IWatcherService.java \
   RedirOutputThread.java \
   R.java \
   WatcherMain.java \
   WatcherReceiver.java \
   WatcherService.java \
   $(NULL)
@@ -29,43 +27,46 @@ RES_FILES = \
   res/drawable-mdpi/ateamlogo.png \
   res/layout/main.xml \
   res/values/strings.xml \
   $(NULL)
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  $(ANDROID_APK_NAME).ap_ \
-  $(ANDROID_APK_NAME)-unsigned-unaligned.apk \
-  $(ANDROID_APK_NAME)-unaligned.apk \
-  $(ANDROID_APK_NAME).apk \
+  Watcher.apk  \
   $(NULL)
 
 GARBAGE_DIRS += res classes network-libs
 
 JAVA_CLASSPATH = $(ANDROID_SDK)/android.jar
 
 include $(topsrcdir)/config/rules.mk
 
 # include Android specific java flags - using these instead of what's in rules.mk
 include $(topsrcdir)/config/android-common.mk
 
-tools:: $(ANDROID_APK_NAME).apk
+tools:: Watcher.apk
 
 classes.dex: $(JAVAFILES)
 	$(NSINSTALL) -D classes
 	$(JAVAC) $(JAVAC_FLAGS) -d classes  $(addprefix $(srcdir)/,$(JAVAFILES))
 	$(DX) --dex --output=$@ classes
 
-$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
-	$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
+Watcher.ap_: $(srcdir)/AndroidManifest.xml
+	$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
 
-$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
-	cp $< $@
-	$(ZIP) -v0 $@ classes.dex
+Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex
+	$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex
 
-$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
-	cp $< $@
-	$(DEBUG_JARSIGNER) $@
+Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk
+	cp  Watcher-unsigned-unaligned.apk $@
+ifdef JARSIGNER
+  $(JARSIGNER) $@
+endif
 
-$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
-	$(ZIPALIGN) -f -v 4 $< $@
+Watcher.apk: Watcher-unaligned.apk
+	$(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@
+
+export::
+	$(NSINSTALL) -D res
+	@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -)
+
--- a/build/unix/stdc++compat/Makefile.in
+++ b/build/unix/stdc++compat/Makefile.in
@@ -5,17 +5,16 @@
 DEPTH		= @DEPTH@
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 LIBRARY_NAME	= stdc++compat
-DISABLED_HOST_LIBRARY_NAME = host_stdc++compat
 FORCE_STATIC_LIB= 1
 STL_FLAGS =
 NO_EXPAND_LIBS = 1
 NO_PROFILE_GUIDED_OPTIMIZE = 1
 
   $(NULL)
 
 HOST_CPPSRCS = $(CPPSRCS)
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -369,17 +369,17 @@ private:
     nsScriptSecurityManager();
     virtual ~nsScriptSecurityManager();
 
     bool SubjectIsPrivileged();
 
     static JSBool
     CheckObjectAccess(JSContext *cx, JSHandleObject obj,
                       JSHandleId id, JSAccessMode mode,
-                      JSMutableHandleValue vp);
+                      JS::MutableHandle<JS::Value> vp);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
     static nsIPrincipal* doGetObjectPrincipal(JS::Handle<JSObject*> obj);
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -481,17 +481,17 @@ nsScriptSecurityManager::ContentSecurity
 
     return evalOK;
 }
 
 
 JSBool
 nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSHandleObject obj,
                                            JSHandleId id, JSAccessMode mode,
-                                           JSMutableHandleValue vp)
+                                           JS::MutableHandle<JS::Value> vp)
 {
     // Get the security manager
     nsScriptSecurityManager *ssm =
         nsScriptSecurityManager::GetScriptSecurityManager();
 
     NS_ASSERTION(ssm, "Failed to get security manager service");
     if (!ssm)
         return JS_FALSE;
--- a/config/android-common.mk
+++ b/config/android-common.mk
@@ -9,19 +9,22 @@ ifndef ANDROID_SDK
 endif
 
 ifndef JAVA_CLASSPATH
   $(error JAVA_CLASSPATH must be defined before including android-common.mk)
 endif
 
 DX=$(ANDROID_BUILD_TOOLS)/dx
 AAPT=$(ANDROID_BUILD_TOOLS)/aapt
+APKBUILDER=$(ANDROID_SDK)/../../tools/apkbuilder
 ZIPALIGN=$(ANDROID_SDK)/../../tools/zipalign
-# DEBUG_JARSIGNER always debug signs.
-DEBUG_JARSIGNER=$(PYTHON) $(call core_abspath,$(topsrcdir)/mobile/android/debug_sign_tool.py)
+
+ifdef JARSIGNER
+  APKBUILDER_FLAGS += -u
+endif
 
 # For Android, this defaults to $(ANDROID_SDK)/android.jar
 ifndef JAVA_BOOTCLASSPATH
   JAVA_BOOTCLASSPATH = $(ANDROID_SDK)/android.jar:$(ANDROID_COMPAT_LIB)
 endif
 
 # For Android, we default to 1.5
 ifndef JAVA_VERSION
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -12,16 +12,17 @@ endif
 
 # Integrate with mozbuild-generated make files. We first verify that no
 # variables provided by the automatically generated .mk files are
 # present. If they are, this is a violation of the separation of
 # responsibility between Makefile.in and mozbuild files.
 _MOZBUILD_EXTERNAL_VARIABLES := \
   DIRS \
   HOST_CSRCS \
+  HOST_LIBRARY_NAME \
   MODULE \
   PARALLEL_DIRS \
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPIDL_MODULE \
   $(NULL)
 
--- a/content/base/public/nsContentCID.h
+++ b/content/base/public/nsContentCID.h
@@ -38,26 +38,16 @@
 // {e7ba1480-1dea-11d3-830f-00104bed045e}
 #define NS_TEXT_ENCODER_CID \
 { 0xe7ba1480, 0x1dea, 0x11d3, {0x83, 0x0f, 0x00, 0x10, 0x4b, 0xed, 0x04, 0x5e} }
 
  // {7f915b01-98fc-11d4-8eb0-a803f80ff1bc}
 #define NS_HTMLCOPY_TEXT_ENCODER_CID \
 { 0x7f915b01, 0x98fc, 0x11d4, { 0x8e, 0xb0, 0xa8, 0x03, 0xf8, 0x0f, 0xf1, 0xbc } }
 
-#define NS_HTMLIMAGEELEMENT_CID                   \
-{ /* d6008c40-4dad-11d2-b328-00805f8a3859 */      \
- 0xd6008c40, 0x4dad, 0x11d2,                      \
- {0xb3, 0x28, 0x00, 0x80, 0x5f, 0x8a, 0x38, 0x59}}
-
-#define NS_HTMLOPTIONELEMENT_CID                  \
-{ /* a6cf90f5-15b3-11d2-932e-00805f8add32 */      \
- 0xa6cf90f5, 0x15b3, 0x11d2,                      \
- {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}}
-
 #define NS_NAMESPACEMANAGER_CID                   \
 { /* d9783472-8fe9-11d2-9d3c-0060088f9ff7 */      \
  0xd9783472, 0x8fe9, 0x11d2,                      \
  {0x9d, 0x3c, 0x00, 0x60, 0x08, 0x8f, 0x9f, 0xf7}}
 
 #define NS_CONTENTITERATOR_CID \
 {/* {a6cf90e3-15b3-11d2-932e-00805f8add32}*/ \
  0xa6cf90e3, 0x15b3, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } }
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -272,17 +272,17 @@ public:
   // Among the sub-classes that inherit (directly or indirectly) from nsINode,
   // measurement of the following members may be added later if DMD finds it is
   // worthwhile:
   // - nsGenericHTMLElement:  mForm, mFieldSet
   // - nsGenericHTMLFrameElement: mFrameLoader (bug 672539)
   // - HTMLBodyElement:       mContentStyleRule
   // - HTMLDataListElement:   mOptions
   // - HTMLFieldSetElement:   mElements, mDependentElements, mFirstLegend
-  // - nsHTMLFormElement:     many!
+  // - HTMLFormElement:       many!
   // - HTMLFrameSetElement:   mRowSpecs, mColSpecs
   // - HTMLInputElement:      mInputData, mFiles, mFileList, mStaticDocfileList
   // - nsHTMLMapElement:      mAreas
   // - HTMLMediaElement:      many!
   // - nsHTMLOutputElement:   mDefaultValue, mTokenList
   // - nsHTMLRowElement:      mCells
   // - nsHTMLSelectElement:   mOptions, mRestoreState
   // - nsHTMLTableElement:    mTBodies, mRows, mTableInheritedAttributes
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1860,18 +1860,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
 
   tmp->mRadioGroups.Clear();
 
   // nsDocument has a pretty complex destructor, so we're going to
   // assume that *most* cycles you actually want to break somewhere
   // else, and not unlink an awful lot here.
 
   tmp->mIdentifierMap.Clear();
-  ++tmp->mExpandoAndGeneration.generation;
-  tmp->mExpandoAndGeneration.expando = JS::UndefinedValue();
+  tmp->mExpandoAndGeneration.Unlink();
 
   tmp->mCustomPrototypes.Clear();
 
   if (tmp->mAnimationController) {
     tmp->mAnimationController->Unlink();
   }
 
   tmp->mPendingTitleChangeEvent.Revoke();
--- a/content/base/src/nsFormData.cpp
+++ b/content/base/src/nsFormData.cpp
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsFormData.h"
 #include "nsIVariant.h"
 #include "nsIInputStream.h"
 #include "nsIDOMFile.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/FormDataBinding.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsFormData::nsFormData(nsISupports* aOwner)
   : nsFormSubmission(NS_LITERAL_CSTRING("UTF-8"), nullptr)
@@ -104,23 +104,22 @@ nsFormData::Append(const nsAString& aNam
 /* virtual */ JSObject*
 nsFormData::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return FormDataBinding::Wrap(aCx, aScope, this);
 }
 
 /* static */ already_AddRefed<nsFormData>
 nsFormData::Constructor(const GlobalObject& aGlobal,
-                        const Optional<nsHTMLFormElement*>& aFormElement,
+                        const Optional<NonNull<HTMLFormElement> >& aFormElement,
                         ErrorResult& aRv)
 {
   nsRefPtr<nsFormData> formData = new nsFormData(aGlobal.Get());
   if (aFormElement.WasPassed()) {
-    MOZ_ASSERT(aFormElement.Value());
-    aRv = aFormElement.Value()->WalkFormElements(formData);
+    aRv = aFormElement.Value().WalkFormElements(formData);
   }
   return formData.forget();
 }
 
 // -------------------------------------------------------------------------
 // nsIXHRSendable
 
 NS_IMETHODIMP
--- a/content/base/src/nsFormData.h
+++ b/content/base/src/nsFormData.h
@@ -9,23 +9,23 @@
 #include "nsIDOMFormData.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsFormSubmission.h"
 #include "nsWrapperCache.h"
 #include "nsTArray.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 
-class nsHTMLFormElement;
 class nsIDOMFile;
 
 namespace mozilla {
 class ErrorResult;
 
 namespace dom {
+class HTMLFormElement;
 class GlobalObject;
 } // namespace dom
 } // namespace mozilla
 
 class nsFormData : public nsIDOMFormData,
                    public nsIXHRSendable,
                    public nsFormSubmission,
                    public nsWrapperCache
@@ -47,17 +47,17 @@ public:
   // WebIDL
   nsISupports*
   GetParentObject() const
   {
     return mOwner;
   }
   static already_AddRefed<nsFormData>
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
-              const mozilla::dom::Optional<nsHTMLFormElement*>& aFormElement,
+              const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, const nsAString& aValue);
   void Append(const nsAString& aName, nsIDOMBlob* aBlob,
               const mozilla::dom::Optional<nsAString>& aFilename);
 
   // nsFormSubmission
   virtual nsresult GetEncodedSubmission(nsIURI* aURI,
                                         nsIInputStream** aPostDataStream) MOZ_OVERRIDE;
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -293,17 +293,17 @@ nsFrameLoader::nsFrameLoader(Element* aO
   ResetPermissionManagerStatus();
 }
 
 nsFrameLoader*
 nsFrameLoader::Create(Element* aOwner, bool aNetworkCreated)
 {
   NS_ENSURE_TRUE(aOwner, nullptr);
   nsIDocument* doc = aOwner->OwnerDoc();
-  NS_ENSURE_TRUE(!doc->GetDisplayDocument() &&
+  NS_ENSURE_TRUE(!doc->IsResourceDoc() &&
                  ((!doc->IsLoadedAsData() && aOwner->GetCurrentDoc()) ||
                    doc->IsStaticDocument()),
                  nullptr);
 
   return new nsFrameLoader(aOwner, aNetworkCreated);
 }
 
 NS_IMETHODIMP
@@ -1787,17 +1787,17 @@ nsresult
 nsFrameLoader::GetWindowDimensions(nsRect& aRect)
 {
   // Need to get outer window position here
   nsIDocument* doc = mOwnerContent->GetDocument();
   if (!doc) {
     return NS_ERROR_FAILURE;
   }
 
-  if (doc->GetDisplayDocument()) {
+  if (doc->IsResourceDoc()) {
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIWebNavigation> parentAsWebNav =
     do_GetInterface(doc->GetScriptGlobalObject());
 
   if (!parentAsWebNav) {
     return NS_ERROR_FAILURE;
@@ -1962,17 +1962,17 @@ nsFrameLoader::TryRemoteBrowser()
 {
   NS_ASSERTION(!mRemoteBrowser, "TryRemoteBrowser called with a remote browser already?");
 
   nsIDocument* doc = mOwnerContent->GetDocument();
   if (!doc) {
     return false;
   }
 
-  if (doc->GetDisplayDocument()) {
+  if (doc->IsResourceDoc()) {
     // Don't allow subframe loads in external reference documents
     return false;
   }
 
   nsCOMPtr<nsIWebNavigation> parentAsWebNav =
     do_GetInterface(doc->GetScriptGlobalObject());
 
   if (!parentAsWebNav) {
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -1056,18 +1056,50 @@ NS_IMETHODIMP
 nsObjectLoadingContent::GetContentTypeForMIMEType(const nsACString& aMIMEType,
                                                   uint32_t* aType)
 {
   *aType = GetTypeOfContent(PromiseFlatCString(aMIMEType));
   return NS_OK;
 }
 
 // nsIInterfaceRequestor
+// We use a shim class to implement this so that JS consumers still
+// see an interface requestor even though WebIDL bindings don't expose
+// that stuff.
+class ObjectInterfaceRequestorShim MOZ_FINAL : public nsIInterfaceRequestor,
+                                               public nsIChannelEventSink
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ObjectInterfaceRequestorShim,
+                                           nsIInterfaceRequestor)
+  NS_DECL_NSIINTERFACEREQUESTOR
+  NS_FORWARD_NSICHANNELEVENTSINK(mContent->)
+
+  ObjectInterfaceRequestorShim(nsIChannelEventSink* aContent)
+    : mContent(aContent)
+  {}
+
+protected:
+  nsRefPtr<nsIChannelEventSink> mContent;
+};
+
+NS_IMPL_CYCLE_COLLECTION_1(ObjectInterfaceRequestorShim, mContent)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ObjectInterfaceRequestorShim)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
+  NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(ObjectInterfaceRequestorShim)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(ObjectInterfaceRequestorShim)
+
 NS_IMETHODIMP
-nsObjectLoadingContent::GetInterface(const nsIID & aIID, void **aResult)
+ObjectInterfaceRequestorShim::GetInterface(const nsIID & aIID, void **aResult)
 {
   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
     nsIChannelEventSink* sink = this;
     *aResult = sink;
     NS_ADDREF(sink);
     return NS_OK;
   }
   return NS_NOINTERFACE;
@@ -2074,17 +2106,19 @@ nsObjectLoadingContent::OpenChannel()
   nsCOMPtr<nsIContentSecurityPolicy> csp;
   rv = doc->NodePrincipal()->GetCsp(getter_AddRefs(csp));
   NS_ENSURE_SUCCESS(rv, rv);
   if (csp) {
     channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
     channelPolicy->SetContentSecurityPolicy(csp);
     channelPolicy->SetLoadType(nsIContentPolicy::TYPE_OBJECT);
   }
-  rv = NS_NewChannel(getter_AddRefs(chan), mURI, nullptr, group, this,
+  nsRefPtr<ObjectInterfaceRequestorShim> shim =
+    new ObjectInterfaceRequestorShim(this);
+  rv = NS_NewChannel(getter_AddRefs(chan), mURI, nullptr, group, shim,
                      nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
                      nsIChannel::LOAD_CLASSIFY_URI,
                      channelPolicy);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Referrer
   nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
   if (httpChan) {
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -11,17 +11,16 @@
  */
 
 #ifndef NSOBJECTLOADINGCONTENT_H_
 #define NSOBJECTLOADINGCONTENT_H_
 
 #include "mozilla/Attributes.h"
 #include "nsImageLoadingContent.h"
 #include "nsIStreamListener.h"
-#include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsIRunnable.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsIThreadInternal.h"
 #include "nsIFrame.h"
 #include "nsIFrameLoader.h"
 
@@ -31,17 +30,16 @@ class AutoSetInstantiatingToFalse;
 class nsObjectFrame;
 class nsFrameLoader;
 class nsXULElement;
 
 class nsObjectLoadingContent : public nsImageLoadingContent
                              , public nsIStreamListener
                              , public nsIFrameLoaderOwner
                              , public nsIObjectLoadingContent
-                             , public nsIInterfaceRequestor
                              , public nsIChannelEventSink
 {
   friend class AutoSetInstantiatingToFalse;
   friend class AutoSetLoadingToFalse;
   friend class CheckPluginStopEvent;
   friend class nsStopPluginRunnable;
   friend class nsAsyncInstantiateEvent;
 
@@ -95,17 +93,16 @@ class nsObjectLoadingContent : public ns
 
     nsObjectLoadingContent();
     virtual ~nsObjectLoadingContent();
 
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIFRAMELOADEROWNER
     NS_DECL_NSIOBJECTLOADINGCONTENT
-    NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSICHANNELEVENTSINK
 
     /**
      * Object state. This is a bitmask of NS_EVENT_STATEs epresenting the
      * current state of the object.
      */
     nsEventStates ObjectState() const;
 
--- a/content/base/test/chrome/test_bug391728.html
+++ b/content/base/test/chrome/test_bug391728.html
@@ -53,18 +53,18 @@ function init_test() {
   if (!PluginUtils.withTestPlugin(start_test))
     SimpleTest.finish();
 }
 
 function updateBlocklist(aCallback) {
   var blocklistNotifier = Components.classes["@mozilla.org/extensions/blocklist;1"]
                           .getService(Components.interfaces.nsITimerCallback);
   var observer = function() {
-    aCallback();
     Services.obs.removeObserver(observer, "blocklist-updated");
+    SimpleTest.executeSoon(aCallback);
   };
   Services.obs.addObserver(observer, "blocklist-updated", false);
   blocklistNotifier.notify(null);
 }
 
 var _originalBlocklistURL = null;
 function setAndUpdateBlocklist(aURL, aCallback) {
   info("Setting blocklist to " + aURL);
--- a/content/events/src/nsIMEStateManager.cpp
+++ b/content/events/src/nsIMEStateManager.cpp
@@ -26,17 +26,17 @@
 #include "nsISelectionListener.h"
 #include "nsISelectionController.h"
 #include "nsIMutationObserver.h"
 #include "nsContentEventHandler.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "nsIFormControl.h"
 #include "nsIForm.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/Attributes.h"
 #include "nsEventDispatcher.h"
 #include "TextComposition.h"
 #include "mozilla/Preferences.h"
 #include "nsAsyncDOMEvent.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
@@ -482,17 +482,17 @@ nsIMEStateManager::SetIMEState(const IME
       mozilla::dom::Element* formElement = control->GetFormElement();
       nsCOMPtr<nsIForm> form;
       if (control) {
         // is this a form and does it have a default submit element?
         if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) {
           willSubmit = true;
         // is this an html form and does it only have a single text input element?
         } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() &&
-                   static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) {
+                   static_cast<dom::HTMLFormElement*>(formElement)->HasSingleTextControl()) {
           willSubmit = true;
         }
       }
       context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH
                                                 ? NS_LITERAL_STRING("search")
                                                 : NS_LITERAL_STRING("go")
                                             : formElement
                                                 ? NS_LITERAL_STRING("next")
--- a/content/html/content/src/HTMLButtonElement.cpp
+++ b/content/html/content/src/HTMLButtonElement.cpp
@@ -24,17 +24,17 @@
 #include "nsIDocument.h"
 #include "nsGUIEvent.h"
 #include "nsUnicharUtils.h"
 #include "nsLayoutUtils.h"
 #include "nsEventDispatcher.h"
 #include "nsPresState.h"
 #include "nsError.h"
 #include "nsFocusManager.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "mozAutoDocUpdate.h"
 
 #define NS_IN_SUBMIT_CLICK      (1 << 0)
 #define NS_OUTER_ACTIVATE_EVENT (1 << 1)
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Button)
 
 namespace mozilla {
@@ -366,17 +366,17 @@ HTMLButtonElement::PostHandleEvent(nsEve
                           mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
                           // We know the element is a submit control, if this check is moved,
                           // make sure formnovalidate is used only if it's a submit control.
                           HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) ||
                           mForm->CheckValidFormSubmission())) {
           // TODO: removing this code and have the submit event sent by the form
           // see bug 592124.
           // Hold a strong ref while dispatching
-          nsRefPtr<nsHTMLFormElement> form(mForm);
+          nsRefPtr<HTMLFormElement> form(mForm);
           presShell->HandleDOMEventWithTarget(mForm, &event, &status);
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
       }
     }
   } else if ((aVisitor.mItemFlags & NS_IN_SUBMIT_CLICK) && mForm) {
     // Tell the form to flush a possible pending submission.
     // the reason is that the script returned false (the event was
--- a/content/html/content/src/HTMLFieldSetElement.h
+++ b/content/html/content/src/HTMLFieldSetElement.h
@@ -5,17 +5,17 @@
 
 #ifndef mozilla_dom_HTMLFieldSetElement_h
 #define mozilla_dom_HTMLFieldSetElement_h
 
 #include "mozilla/Attributes.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLFieldSetElement.h"
 #include "nsIConstraintValidation.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/ValidityState.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLFieldSetElement : public nsGenericHTMLFormElement,
                             public nsIDOMHTMLFieldSetElement,
                             public nsIConstraintValidation
rename from content/html/content/src/nsHTMLFormElement.cpp
rename to content/html/content/src/HTMLFormElement.cpp
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/HTMLFormElement.cpp
@@ -1,13 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "nsHTMLFormElement.h"
+
+#include "mozilla/dom/HTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElementBinding.h"
 #include "nsIHTMLDocument.h"
 #include "nsEventStateManager.h"
 #include "nsEventStates.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsIDocument.h"
 #include "nsIFormControlFrame.h"
@@ -52,43 +54,63 @@
 #include "nsIDOMHTMLButtonElement.h"
 #include "mozilla/dom/HTMLCollectionBinding.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "nsSandboxFlags.h"
 
 // images
 #include "mozilla/dom/HTMLImageElement.h"
 
-using namespace mozilla::dom;
+DOMCI_NODE_DATA(HTMLFormElement, mozilla::dom::HTMLFormElement)
+
+// construction, destruction
+nsGenericHTMLElement*
+NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo,
+                      mozilla::dom::FromParser aFromParser)
+{
+  mozilla::dom::HTMLFormElement* it = new mozilla::dom::HTMLFormElement(aNodeInfo);
+
+  nsresult rv = it->Init();
+
+  if (NS_FAILED(rv)) {
+    delete it;
+    return nullptr;
+  }
+
+  return it;
+}
+
+namespace mozilla {
+namespace dom {
 
 static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
 
 static const uint8_t NS_FORM_AUTOCOMPLETE_ON  = 1;
 static const uint8_t NS_FORM_AUTOCOMPLETE_OFF = 0;
 
 static const nsAttrValue::EnumTable kFormAutocompleteTable[] = {
   { "on",  NS_FORM_AUTOCOMPLETE_ON },
   { "off", NS_FORM_AUTOCOMPLETE_OFF },
   { 0 }
 };
 // Default autocomplete value is 'on'.
 static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0];
 
-// nsHTMLFormElement
-
-bool nsHTMLFormElement::gFirstFormSubmitted = false;
-bool nsHTMLFormElement::gPasswordManagerInitialized = false;
+// HTMLFormElement
+
+bool HTMLFormElement::gFirstFormSubmitted = false;
+bool HTMLFormElement::gPasswordManagerInitialized = false;
 
 
 // nsFormControlList
 class nsFormControlList : public nsIHTMLCollection,
                           public nsWrapperCache
 {
 public:
-  nsFormControlList(nsHTMLFormElement* aForm);
+  nsFormControlList(HTMLFormElement* aForm);
   virtual ~nsFormControlList();
 
   nsresult Init();
 
   void DropFormReference();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
@@ -129,17 +151,17 @@ public:
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx,
                                JS::Handle<JSObject*> scope) MOZ_OVERRIDE
   {
     return HTMLCollectionBinding::Wrap(cx, scope, this);
   }
 
-  nsHTMLFormElement* mForm;  // WEAK - the form owns me
+  HTMLFormElement* mForm;  // WEAK - the form owns me
 
   nsTArray<nsGenericHTMLFormElement*> mElements;  // Holds WEAK references - bug 36639
 
   // This array holds on to all form controls that are not contained
   // in mElements (form.elements in JS, see ShouldBeInFormControl()).
   // This is needed to properly clean up the bi-directional references
   // (both weak and strong) between the form and its form controls.
 
@@ -204,36 +226,19 @@ ShouldBeInElements(nsIFormControl* aForm
   // form.elements array
   //
   // NS_FORM_INPUT_IMAGE
   // NS_FORM_LABEL
 
   return false;
 }
 
-// nsHTMLFormElement implementation
-
-// construction, destruction
-nsGenericHTMLElement*
-NS_NewHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                      FromParser aFromParser)
-{
-  nsHTMLFormElement* it = new nsHTMLFormElement(aNodeInfo);
-
-  nsresult rv = it->Init();
-
-  if (NS_FAILED(rv)) {
-    delete it;
-    return nullptr;
-  }
-
-  return it;
-}
-
-nsHTMLFormElement::nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
+// HTMLFormElement implementation
+
+HTMLFormElement::HTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mGeneratingSubmit(false),
     mGeneratingReset(false),
     mIsSubmitting(false),
     mDeferSubmission(false),
     mNotifiedObservers(false),
     mNotifiedObserversResult(false),
     mSubmitPopupState(openAbused),
@@ -243,29 +248,31 @@ nsHTMLFormElement::nsHTMLFormElement(alr
     mDefaultSubmitElement(nullptr),
     mFirstSubmitInElements(nullptr),
     mFirstSubmitNotInElements(nullptr),
     mInvalidElementsCount(0),
     mEverTriedInvalidSubmit(false)
 {
   mImageNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
   mPastNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
+
+  SetIsDOMBinding();
 }
 
-nsHTMLFormElement::~nsHTMLFormElement()
+HTMLFormElement::~HTMLFormElement()
 {
   if (mControls) {
     mControls->DropFormReference();
   }
 
   Clear();
 }
 
 nsresult
-nsHTMLFormElement::Init()
+HTMLFormElement::Init()
 {
   mControls = new nsFormControlList(this);
   if (!mControls) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   nsresult rv = mControls->Init();
   
@@ -291,64 +298,76 @@ ElementTraverser(const nsAString& key, n
 {
   nsCycleCollectionTraversalCallback *cb = 
     static_cast<nsCycleCollectionTraversalCallback*>(userArg);
  
   cb->NoteXPCOMChild(element);
   return PL_DHASH_NEXT;
 }
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFormElement,
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLFormElement,
                                                   nsGenericHTMLElement)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControls)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable)
   tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLFormElement,
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement,
                                                 nsGenericHTMLElement)
   tmp->Clear();
+  tmp->mExpandoAndGeneration.Unlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_IMPL_ADDREF_INHERITED(nsHTMLFormElement, Element)
-NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, Element)
-
-
-DOMCI_NODE_DATA(HTMLFormElement, nsHTMLFormElement)
-
-// QueryInterface implementation for nsHTMLFormElement
-NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLFormElement)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(HTMLFormElement,
+                                               nsGenericHTMLElement)
+  if (tmp->PreservingWrapper()) {
+    NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando);
+  }
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_ADDREF_INHERITED(HTMLFormElement, Element)
+NS_IMPL_RELEASE_INHERITED(HTMLFormElement, Element)
+
+
+// QueryInterface implementation for HTMLFormElement
+NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLFormElement)
   NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement)
-  NS_INTERFACE_TABLE_INHERITED4(nsHTMLFormElement,
+  NS_INTERFACE_TABLE_INHERITED4(HTMLFormElement,
                                 nsIDOMHTMLFormElement,
                                 nsIForm,
                                 nsIWebProgressListener,
                                 nsIRadioGroupContainer)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLFormElement)
 NS_ELEMENT_INTERFACE_MAP_END
 
 
 // nsIDOMHTMLFormElement
 
-NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsHTMLFormElement)
+NS_IMPL_ELEMENT_CLONE_WITH_INIT(HTMLFormElement)
+
+nsIHTMLCollection*
+HTMLFormElement::Elements()
+{
+  return mControls;
+}
 
 NS_IMETHODIMP
-nsHTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements)
+HTMLFormElement::GetElements(nsIDOMHTMLCollection** aElements)
 {
-  *aElements = mControls;
+  *aElements = Elements();
   NS_ADDREF(*aElements);
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                           nsIAtom* aPrefix, const nsAString& aValue,
-                           bool aNotify)
+HTMLFormElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                         nsIAtom* aPrefix, const nsAString& aValue,
+                         bool aNotify)
 {
   if ((aName == nsGkAtoms::action || aName == nsGkAtoms::target) &&
       aNameSpaceID == kNameSpaceID_None) {
     if (mPendingSubmission) {
       // aha, there is a pending submission that means we're in
       // the script and we need to flush it. let's tell it
       // that the event was ignored to force the flush.
       // the second argument is not playing a role at all.
@@ -360,18 +379,18 @@ nsHTMLFormElement::SetAttr(int32_t aName
     ForgetCurrentSubmission();
     mNotifiedObservers = notifiedObservers;
   }
   return nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
                                        aNotify);
 }
 
 nsresult
-nsHTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
-                                const nsAttrValue* aValue, bool aNotify)
+HTMLFormElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
+                              const nsAttrValue* aValue, bool aNotify)
 {
   if (aName == nsGkAtoms::novalidate && aNameSpaceID == kNameSpaceID_None) {
     // Update all form elements states because they might be [no longer]
     // affected by :-moz-ui-valid or :-moz-ui-invalid.
     for (uint32_t i = 0, length = mControls->mElements.Length();
          i < length; ++i) {
       mControls->mElements[i]->UpdateState(true);
     }
@@ -380,67 +399,73 @@ nsHTMLFormElement::AfterSetAttr(int32_t 
          i < length; ++i) {
       mControls->mNotInElements[i]->UpdateState(true);
     }
   }
 
   return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
 }
 
-NS_IMPL_STRING_ATTR(nsHTMLFormElement, AcceptCharset, acceptcharset)
-NS_IMPL_ACTION_ATTR(nsHTMLFormElement, Action, action)
-NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Autocomplete, autocomplete,
+NS_IMPL_STRING_ATTR(HTMLFormElement, AcceptCharset, acceptcharset)
+NS_IMPL_ACTION_ATTR(HTMLFormElement, Action, action)
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Autocomplete, autocomplete,
                                 kFormDefaultAutocomplete->tag)
-NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Enctype, enctype,
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Enctype, enctype,
                                 kFormDefaultEnctype->tag)
-NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLFormElement, Method, method,
+NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLFormElement, Method, method,
                                 kFormDefaultMethod->tag)
-NS_IMPL_BOOL_ATTR(nsHTMLFormElement, NoValidate, novalidate)
-NS_IMPL_STRING_ATTR(nsHTMLFormElement, Name, name)
-NS_IMPL_STRING_ATTR(nsHTMLFormElement, Target, target)
-
-NS_IMETHODIMP
-nsHTMLFormElement::Submit()
+NS_IMPL_BOOL_ATTR(HTMLFormElement, NoValidate, novalidate)
+NS_IMPL_STRING_ATTR(HTMLFormElement, Name, name)
+NS_IMPL_STRING_ATTR(HTMLFormElement, Target, target)
+
+void
+HTMLFormElement::Submit(ErrorResult& aRv)
 {
   // Send the submit event
-  nsresult rv = NS_OK;
   nsRefPtr<nsPresContext> presContext = GetPresContext();
   if (mPendingSubmission) {
     // aha, we have a pending submission that was not flushed
     // (this happens when form.submit() is called twice)
     // we have to delete it and build a new one since values
     // might have changed inbetween (we emulate IE here, that's all)
     mPendingSubmission = nullptr;
   }
 
-  rv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT);
-  return rv;
+  aRv = DoSubmitOrReset(nullptr, NS_FORM_SUBMIT);
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::Reset()
+HTMLFormElement::Submit()
+{
+  ErrorResult rv;
+  Submit(rv);
+  return rv.ErrorCode();
+}
+
+NS_IMETHODIMP
+HTMLFormElement::Reset()
 {
   nsFormEvent event(true, NS_FORM_RESET);
   nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this), nullptr,
                               &event);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::CheckValidity(bool* retVal)
+HTMLFormElement::CheckValidity(bool* retVal)
 {
-  *retVal = CheckFormValidity(nullptr);
+  *retVal = CheckValidity();
   return NS_OK;
 }
 
 bool
-nsHTMLFormElement::ParseAttribute(int32_t aNamespaceID,
-                                  nsIAtom* aAttribute,
-                                  const nsAString& aValue,
-                                  nsAttrValue& aResult)
+HTMLFormElement::ParseAttribute(int32_t aNamespaceID,
+                                nsIAtom* aAttribute,
+                                const nsAString& aValue,
+                                nsAttrValue& aResult)
 {
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::method) {
       return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
     }
     if (aAttribute == nsGkAtoms::enctype) {
       return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
     }
@@ -449,19 +474,19 @@ nsHTMLFormElement::ParseAttribute(int32_
     }
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
 }
 
 nsresult
-nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
-                              nsIContent* aBindingParent,
-                              bool aCompileEventHandlers)
+HTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
+                            nsIContent* aBindingParent,
+                            bool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(aDocument));
   if (htmlDoc) {
@@ -563,17 +588,17 @@ CollectOrphans(nsINode* aRemovalRoot,
       nsCOMPtr<nsIDOMHTMLFormElement> form = node->GetForm();
       NS_ASSERTION(form == aThisForm, "How did that happen?");
     }
 #endif /* DEBUG */
   }
 }
 
 void
-nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
+HTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   nsCOMPtr<nsIHTMLDocument> oldDocument = do_QueryInterface(GetCurrentDoc());
 
   // Mark all of our controls as maybe being orphans
   MarkOrphans(mControls->mElements);
   MarkOrphans(mControls->mNotInElements);
   MarkOrphans(mImageElements);
 
@@ -607,17 +632,17 @@ nsHTMLFormElement::UnbindFromTree(bool a
 
   if (oldDocument) {
     oldDocument->RemovedForm();
   }
   ForgetCurrentSubmission();
 }
 
 nsresult
-nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
+HTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
 {
   aVisitor.mWantsWillHandleEvent = true;
   if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
     uint32_t msg = aVisitor.mEvent->message;
     if (msg == NS_FORM_SUBMIT) {
       if (mGeneratingSubmit) {
         aVisitor.mCanHandle = false;
         return NS_OK;
@@ -636,32 +661,32 @@ nsHTMLFormElement::PreHandleEvent(nsEven
       }
       mGeneratingReset = true;
     }
   }
   return nsGenericHTMLElement::PreHandleEvent(aVisitor);
 }
 
 nsresult
-nsHTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor)
+HTMLFormElement::WillHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   // If this is the bubble stage and there is a nested form below us which
   // received a submit event we do *not* want to handle the submit event
   // for this form too.
   if ((aVisitor.mEvent->message == NS_FORM_SUBMIT ||
        aVisitor.mEvent->message == NS_FORM_RESET) &&
       aVisitor.mEvent->mFlags.mInBubblingPhase &&
       aVisitor.mEvent->originalTarget != static_cast<nsIContent*>(this)) {
     aVisitor.mEvent->mFlags.mPropagationStopped = true;
   }
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
+HTMLFormElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
     uint32_t msg = aVisitor.mEvent->message;
     if (msg == NS_FORM_SUBMIT) {
       // let the form know not to defer subsequent submissions
       mDeferSubmission = false;
     }
 
@@ -698,18 +723,18 @@ nsHTMLFormElement::PostHandleEvent(nsEve
     else if (msg == NS_FORM_RESET) {
       mGeneratingReset = false;
     }
   }
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::DoSubmitOrReset(nsEvent* aEvent,
-                                   int32_t aMessage)
+HTMLFormElement::DoSubmitOrReset(nsEvent* aEvent,
+                                 int32_t aMessage)
 {
   // Make sure the presentation is up-to-date
   nsIDocument* doc = GetCurrentDoc();
   if (doc) {
     doc->FlushPendingNotifications(Flush_ContentAndNotify);
   }
 
   // JBK Don't get form frames anymore - bug 34297
@@ -728,17 +753,17 @@ nsHTMLFormElement::DoSubmitOrReset(nsEve
     return DoSubmit(aEvent);
   }
 
   MOZ_ASSERT(false);
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::DoReset()
+HTMLFormElement::DoReset()
 {
   // JBK walk the elements[] array instead of form frame controls - bug 34297
   uint32_t numElements = GetElementCount();
   for (uint32_t elementX = 0; elementX < numElements; ++elementX) {
     // Hold strong ref in case the reset does something weird
     nsCOMPtr<nsIFormControl> controlNode = GetElementAt(elementX);
     if (controlNode) {
       controlNode->Reset();
@@ -750,17 +775,17 @@ nsHTMLFormElement::DoReset()
 
 #define NS_ENSURE_SUBMIT_SUCCESS(rv)                                          \
   if (NS_FAILED(rv)) {                                                        \
     ForgetCurrentSubmission();                                                \
     return rv;                                                                \
   }
 
 nsresult
-nsHTMLFormElement::DoSubmit(nsEvent* aEvent)
+HTMLFormElement::DoSubmit(nsEvent* aEvent)
 {
   NS_ASSERTION(GetCurrentDoc(), "Should never get here without a current doc");
 
   if (mIsSubmitting) {
     NS_WARNING("Preventing double form submission");
     // XXX Should this return an error?
     return NS_OK;
   }
@@ -804,18 +829,18 @@ nsHTMLFormElement::DoSubmit(nsEvent* aEv
   
   // 
   // perform the submission
   //
   return SubmitSubmission(submission); 
 }
 
 nsresult
-nsHTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission, 
-                                   nsEvent* aEvent)
+HTMLFormElement::BuildSubmission(nsFormSubmission** aFormSubmission, 
+                                 nsEvent* aEvent)
 {
   NS_ASSERTION(!mPendingSubmission, "tried to build two submissions!");
 
   // Get the originating frame (failure is non-fatal)
   nsGenericHTMLElement* originatingElement = nullptr;
   if (aEvent) {
     if (NS_FORM_EVENT == aEvent->eventStructType) {
       nsIContent* originator = ((nsFormEvent *)aEvent)->originator;
@@ -842,17 +867,17 @@ nsHTMLFormElement::BuildSubmission(nsFor
   //
   rv = WalkFormElements(*aFormSubmission);
   NS_ENSURE_SUBMIT_SUCCESS(rv);
 
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
+HTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
 {
   nsresult rv;
   nsIContent* originatingElement = aFormSubmission->GetOriginatingElement();
 
   //
   // Get the action and target
   //
   nsCOMPtr<nsIURI> actionURI;
@@ -976,19 +1001,19 @@ nsHTMLFormElement::SubmitSubmission(nsFo
   } else {
     ForgetCurrentSubmission();
   }
 
   return rv;
 }
 
 nsresult
-nsHTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
-                                         bool* aCancelSubmit,
-                                         bool    aEarlyNotify)
+HTMLFormElement::NotifySubmitObservers(nsIURI* aActionURL,
+                                       bool* aCancelSubmit,
+                                       bool    aEarlyNotify)
 {
   // If this is the first form, bring alive the first form submit
   // category observers
   if (!gFirstFormSubmitted) {
     gFirstFormSubmitted = true;
     NS_CreateServicesFromCategory(NS_FIRST_FORMSUBMIT_CATEGORY,
                                   nullptr,
                                   NS_FIRST_FORMSUBMIT_CATEGORY);
@@ -1035,17 +1060,17 @@ nsHTMLFormElement::NotifySubmitObservers
     }
   }
 
   return rv;
 }
 
 
 nsresult
-nsHTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission)
+HTMLFormElement::WalkFormElements(nsFormSubmission* aFormSubmission)
 {
   nsTArray<nsGenericHTMLFormElement*> sortedControls;
   nsresult rv = mControls->GetSortedControls(sortedControls);
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t len = sortedControls.Length();
 
   // Hold a reference to the elements so they can't be deleted while
@@ -1068,25 +1093,33 @@ nsHTMLFormElement::WalkFormElements(nsFo
   }
 
   return NS_OK;
 }
 
 // nsIForm
 
 NS_IMETHODIMP_(uint32_t)
-nsHTMLFormElement::GetElementCount() const 
+HTMLFormElement::GetElementCount() const 
 {
   uint32_t count = 0;
   mControls->GetLength(&count); 
   return count;
 }
 
+Element*
+HTMLFormElement::IndexedGetter(uint32_t aIndex, bool &aFound)
+{
+  Element* element = mControls->mElements.SafeElementAt(aIndex, nullptr);
+  aFound = element != nullptr;
+  return element;
+}
+
 NS_IMETHODIMP_(nsIFormControl*)
-nsHTMLFormElement::GetElementAt(int32_t aIndex) const
+HTMLFormElement::GetElementAt(int32_t aIndex) const
 {
   return mControls->mElements.SafeElementAt(aIndex, nullptr);
 }
 
 /**
  * Compares the position of aControl1 and aControl2 in the document
  * @param aControl1 First control to compare.
  * @param aControl2 Second control to compare.
@@ -1149,17 +1182,17 @@ AssertDocumentOrder(const nsTArray<nsGen
                                               aForm) < 0,
                    "Form controls not ordered correctly");
     }
   }
 }
 #endif
 
 void
-nsHTMLFormElement::PostPasswordEvent()
+HTMLFormElement::PostPasswordEvent()
 {
   // Don't fire another add event if we have a pending add event.
   if (mFormPasswordEvent.get()) {
     return;
   }
 
   nsRefPtr<FormPasswordEvent> event =
     new FormPasswordEvent(this, NS_LITERAL_STRING("DOMFormHasPassword"));
@@ -1167,17 +1200,17 @@ nsHTMLFormElement::PostPasswordEvent()
   event->PostDOMEvent();
 }
 
 // This function return true if the element, once appended, is the last one in
 // the array.
 template<typename ElementType>
 static bool
 AddElementToList(nsTArray<ElementType*>& aList, ElementType* aChild,
-                 nsHTMLFormElement* aForm)
+                 HTMLFormElement* aForm)
 {
   NS_ASSERTION(aList.IndexOf(aChild) == aList.NoIndex,
                "aChild already in aList");
 
   uint32_t count = aList.Length();
   ElementType* element;
   bool lastElement = false;
 
@@ -1214,18 +1247,18 @@ AddElementToList(nsTArray<ElementType*>&
     // WEAK - don't addref
     aList.InsertElementAt(low, aChild);
   }
 
   return lastElement;
 }
 
 nsresult
-nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
-                              bool aUpdateValidity, bool aNotify)
+HTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
+                            bool aUpdateValidity, bool aNotify)
 {
   // If an element has a @form, we can assume it *might* be able to not have
   // a parent and still be in the form.
   NS_ASSERTION(aChild->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
                aChild->GetParent(),
                "Form control should have a parent");
 
   // Determine whether to add the new element to the elements or
@@ -1319,26 +1352,26 @@ nsHTMLFormElement::AddElement(nsGenericH
       static_cast<HTMLInputElement*>(aChild);
     radio->AddedToRadioGroup();
   }
 
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
-                                     const nsAString& aName)
+HTMLFormElement::AddElementToTable(nsGenericHTMLFormElement* aChild,
+                                   const nsAString& aName)
 {
   return mControls->AddElementToTable(aChild, aName);  
 }
 
 
 nsresult
-nsHTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
-                                 bool aUpdateValidity)
+HTMLFormElement::RemoveElement(nsGenericHTMLFormElement* aChild,
+                               bool aUpdateValidity)
 {
   //
   // Remove it from the radio group if it's a radio button
   //
   nsresult rv = NS_OK;
   if (aChild->GetType() == NS_FORM_INPUT_RADIO) {
     nsRefPtr<HTMLInputElement> radio =
       static_cast<HTMLInputElement*>(aChild);
@@ -1396,17 +1429,17 @@ nsHTMLFormElement::RemoveElement(nsGener
       UpdateValidity(true);
     }
   }
 
   return rv;
 }
 
 void
-nsHTMLFormElement::HandleDefaultSubmitRemoval()
+HTMLFormElement::HandleDefaultSubmitRemoval()
 {
   if (mDefaultSubmitElement) {
     // Already got reset somehow; nothing else to do here
     return;
   }
 
   if (!mFirstSubmitNotInElements) {
     mDefaultSubmitElement = mFirstSubmitInElements;
@@ -1427,30 +1460,31 @@ nsHTMLFormElement::HandleDefaultSubmitRe
                    "What happened here?");
 
   // Notify about change if needed.
   if (mDefaultSubmitElement) {
     mDefaultSubmitElement->UpdateState(true);
   }
 }
 
-static nsresult
-RemoveElementFromTableInternal(
+nsresult
+HTMLFormElement::RemoveElementFromTableInternal(
   nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
   nsIContent* aChild, const nsAString& aName)
 {
   nsCOMPtr<nsISupports> supports;
 
   if (!aTable.Get(aName, getter_AddRefs(supports)))
     return NS_OK;
 
   // Single element in the hash, just remove it if it's the one
   // we're trying to remove...
   if (supports == aChild) {
     aTable.Remove(aName);
+    ++mExpandoAndGeneration.generation;
     return NS_OK;
   }
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(supports));
   if (content) {
     return NS_OK;
   }
 
@@ -1464,16 +1498,17 @@ RemoveElementFromTableInternal(
 
   uint32_t length = 0;
   list->GetLength(&length);
 
   if (!length) {
     // If the list is empty we remove if from our hash, this shouldn't
     // happen tho
     aTable.Remove(aName);
+    ++mExpandoAndGeneration.generation;
   } else if (length == 1) {
     // Only one element left, replace the list in the hash with the
     // single element.
     nsIContent* node = list->Item(0);
     if (node) {
       aTable.Put(aName, node);
     }
   }
@@ -1485,68 +1520,92 @@ static PLDHashOperator
 RemovePastNames(const nsAString& aName,
                 nsCOMPtr<nsISupports>& aData,
                 void* aClosure)
 {
   return aClosure == aData ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
 }
 
 nsresult
-nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
-                                          const nsAString& aName,
-                                          RemoveElementReason aRemoveReason)
+HTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
+                                        const nsAString& aName,
+                                        RemoveElementReason aRemoveReason)
 {
   // If the element is being removed from the form, we have to remove it from
   // the past names map.
   if (aRemoveReason == ElementRemoved) {
+    uint32_t oldCount = mPastNameLookupTable.Count();
     mPastNameLookupTable.Enumerate(RemovePastNames, aElement);
+    if (oldCount != mPastNameLookupTable.Count()) {
+      ++mExpandoAndGeneration.generation;
+    }
   }
 
   return mControls->RemoveElementFromTable(aElement, aName);
 }
 
 already_AddRefed<nsISupports>
-nsHTMLFormElement::FindNamedItem(const nsAString& aName,
-                                 nsWrapperCache** aCache)
+HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound)
 {
+  aFound = true;
+
   nsCOMPtr<nsISupports> result = DoResolveName(aName, true);
   if (result) {
-    // FIXME Get the wrapper cache from DoResolveName.
-    *aCache = nullptr;
     AddToPastNamesMap(aName, result);
     return result.forget();
   }
 
   result = mImageNameLookupTable.GetWeak(aName);
   if (result) {
-    *aCache = nullptr;
     AddToPastNamesMap(aName, result);
     return result.forget();
   }
 
   result = mPastNameLookupTable.GetWeak(aName);
   if (result) {
+    return result.forget();
+  }
+
+  aFound = false;
+  return nullptr;
+}
+
+void
+HTMLFormElement::GetSupportedNames(nsTArray<nsString >& aRetval)
+{
+  // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320
+}
+
+already_AddRefed<nsISupports>
+HTMLFormElement::FindNamedItem(const nsAString& aName,
+                               nsWrapperCache** aCache)
+{
+  // FIXME Get the wrapper cache from DoResolveName.
+
+  bool found;
+  nsCOMPtr<nsISupports> result = NamedGetter(aName, found);
+  if (result) {
     *aCache = nullptr;
     return result.forget();
   }
 
   return nullptr;
 }
 
 already_AddRefed<nsISupports>
-nsHTMLFormElement::DoResolveName(const nsAString& aName,
-                                 bool aFlushContent)
+HTMLFormElement::DoResolveName(const nsAString& aName,
+                               bool aFlushContent)
 {
   nsCOMPtr<nsISupports> result =
     mControls->NamedItemInternal(aName, aFlushContent);
   return result.forget();
 }
 
 void
-nsHTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement)
+HTMLFormElement::OnSubmitClickBegin(nsIContent* aOriginatingElement)
 {
   mDeferSubmission = true;
 
   // Prepare to run NotifySubmitObservers early before the
   // scripts on the page get to modify the form data, possibly
   // throwing off any password manager. (bug 257781)
   nsCOMPtr<nsIURI> actionURI;
   nsresult rv;
@@ -1564,36 +1623,36 @@ nsHTMLFormElement::OnSubmitClickBegin(ns
     if (NS_SUCCEEDED(rv)) {
       mNotifiedObservers = true;
       mNotifiedObserversResult = cancelSubmit;
     }
   }
 }
 
 void
-nsHTMLFormElement::OnSubmitClickEnd()
+HTMLFormElement::OnSubmitClickEnd()
 {
   mDeferSubmission = false;
 }
 
 void
-nsHTMLFormElement::FlushPendingSubmission()
+HTMLFormElement::FlushPendingSubmission()
 {
   if (mPendingSubmission) {
     // Transfer owning reference so that the submissioin doesn't get deleted
     // if we reenter
     nsAutoPtr<nsFormSubmission> submission = mPendingSubmission;
 
     SubmitSubmission(submission);
   }
 }
 
 nsresult
-nsHTMLFormElement::GetActionURL(nsIURI** aActionURL,
-                                nsIContent* aOriginatingElement)
+HTMLFormElement::GetActionURL(nsIURI** aActionURL,
+                              nsIContent* aOriginatingElement)
 {
   nsresult rv = NS_OK;
 
   *aActionURL = nullptr;
 
   //
   // Grab the URL string
   //
@@ -1688,27 +1747,27 @@ nsHTMLFormElement::GetActionURL(nsIURI**
   //
   *aActionURL = actionURL;
   NS_ADDREF(*aActionURL);
 
   return rv;
 }
 
 NS_IMETHODIMP_(nsIFormControl*)
-nsHTMLFormElement::GetDefaultSubmitElement() const
+HTMLFormElement::GetDefaultSubmitElement() const
 {
   NS_PRECONDITION(mDefaultSubmitElement == mFirstSubmitInElements ||
                   mDefaultSubmitElement == mFirstSubmitNotInElements,
                   "What happened here?");
   
   return mDefaultSubmitElement;
 }
 
 bool
-nsHTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
+HTMLFormElement::IsDefaultSubmitElement(const nsIFormControl* aControl) const
 {
   NS_PRECONDITION(aControl, "Unexpected call");
 
   if (aControl == mDefaultSubmitElement) {
     // Yes, it is
     return true;
   }
 
@@ -1733,65 +1792,69 @@ nsHTMLFormElement::IsDefaultSubmitElemen
   nsIFormControl* defaultSubmit =
     CompareFormControlPosition(mFirstSubmitInElements,
                                mFirstSubmitNotInElements, this) < 0 ?
       mFirstSubmitInElements : mFirstSubmitNotInElements;
   return aControl == defaultSubmit;
 }
 
 bool
-nsHTMLFormElement::HasSingleTextControl() const
+HTMLFormElement::HasSingleTextControl() const
 {
   // Input text controls are always in the elements list.
   uint32_t numTextControlsFound = 0;
   uint32_t length = mControls->mElements.Length();
   for (uint32_t i = 0; i < length && numTextControlsFound < 2; ++i) {
     if (mControls->mElements[i]->IsSingleLineTextControl(false)) {
       numTextControlsFound++;
     }
   }
   return numTextControlsFound == 1;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::GetEncoding(nsAString& aEncoding)
+HTMLFormElement::GetEncoding(nsAString& aEncoding)
 {
   return GetEnctype(aEncoding);
 }
  
 NS_IMETHODIMP
-nsHTMLFormElement::SetEncoding(const nsAString& aEncoding)
+HTMLFormElement::SetEncoding(const nsAString& aEncoding)
 {
   return SetEnctype(aEncoding);
 }
 
+int32_t
+HTMLFormElement::Length()
+{
+  return mControls->Length();
+}
+
 NS_IMETHODIMP    
-nsHTMLFormElement::GetLength(int32_t* aLength)
+HTMLFormElement::GetLength(int32_t* aLength)
 {
-  uint32_t length;
-  nsresult rv = mControls->GetLength(&length);
-  *aLength = length;
-  return rv;
+  *aLength = Length();
+  return NS_OK;
 }
 
 void
-nsHTMLFormElement::ForgetCurrentSubmission()
+HTMLFormElement::ForgetCurrentSubmission()
 {
   mNotifiedObservers = false;
   mIsSubmitting = false;
   mSubmittingRequest = nullptr;
   nsCOMPtr<nsIWebProgress> webProgress = do_QueryReferent(mWebProgress);
   if (webProgress) {
     webProgress->RemoveProgressListener(this);
   }
   mWebProgress = nullptr;
 }
 
 bool
-nsHTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const
+HTMLFormElement::CheckFormValidity(nsIMutableArray* aInvalidElements) const
 {
   bool ret = true;
 
   nsTArray<nsGenericHTMLFormElement*> sortedControls;
   if (NS_FAILED(mControls->GetSortedControls(sortedControls))) {
     return false;
   }
 
@@ -1828,17 +1891,17 @@ nsHTMLFormElement::CheckFormValidity(nsI
   for (uint32_t i = 0; i < len; ++i) {
     static_cast<nsGenericHTMLElement*>(sortedControls[i])->Release();
   }
 
   return ret;
 }
 
 bool
-nsHTMLFormElement::CheckValidFormSubmission()
+HTMLFormElement::CheckValidFormSubmission()
 {
   /**
    * Check for form validity: do not submit a form if there are unhandled
    * invalid controls in the form.
    * This should not be done if the form has been submitted with .submit().
    *
    * NOTE: for the moment, we are also checking that there is an observer for
    * NS_INVALIDFORMSUBMIT_SUBJECT so it will prevent blocking form submission
@@ -1943,17 +2006,17 @@ nsHTMLFormElement::CheckValidFormSubmiss
     NS_WARNING("There is no observer for \"invalidformsubmit\". \
 One should be implemented!");
   }
 
   return true;
 }
 
 void
-nsHTMLFormElement::UpdateValidity(bool aElementValidity)
+HTMLFormElement::UpdateValidity(bool aElementValidity)
 {
   if (aElementValidity) {
     --mInvalidElementsCount;
   } else {
     ++mInvalidElementsCount;
   }
 
   NS_ASSERTION(mInvalidElementsCount >= 0, "Something went seriously wrong!");
@@ -1993,99 +2056,99 @@ nsHTMLFormElement::UpdateValidity(bool a
     }
   }
 
   UpdateState(true);
 }
 
 // nsIWebProgressListener
 NS_IMETHODIMP
-nsHTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
-                                 nsIRequest* aRequest,
-                                 uint32_t aStateFlags,
-                                 nsresult aStatus)
+HTMLFormElement::OnStateChange(nsIWebProgress* aWebProgress,
+                               nsIRequest* aRequest,
+                               uint32_t aStateFlags,
+                               nsresult aStatus)
 {
   // If STATE_STOP is never fired for any reason (redirect?  Failed state
   // change?) the form element will leak.  It will be kept around by the
   // nsIWebProgressListener (assuming it keeps a strong pointer).  We will
   // consequently leak the request.
   if (aRequest == mSubmittingRequest &&
       aStateFlags & nsIWebProgressListener::STATE_STOP) {
     ForgetCurrentSubmission();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress,
-                                    nsIRequest* aRequest,
-                                    int32_t aCurSelfProgress,
-                                    int32_t aMaxSelfProgress,
-                                    int32_t aCurTotalProgress,
-                                    int32_t aMaxTotalProgress)
+HTMLFormElement::OnProgressChange(nsIWebProgress* aWebProgress,
+                                  nsIRequest* aRequest,
+                                  int32_t aCurSelfProgress,
+                                  int32_t aMaxSelfProgress,
+                                  int32_t aCurTotalProgress,
+                                  int32_t aMaxTotalProgress)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
-                                    nsIRequest* aRequest,
-                                    nsIURI* location,
-                                    uint32_t aFlags)
+HTMLFormElement::OnLocationChange(nsIWebProgress* aWebProgress,
+                                  nsIRequest* aRequest,
+                                  nsIURI* location,
+                                  uint32_t aFlags)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
-                                  nsIRequest* aRequest,
-                                  nsresult aStatus,
-                                  const PRUnichar* aMessage)
+HTMLFormElement::OnStatusChange(nsIWebProgress* aWebProgress,
+                                nsIRequest* aRequest,
+                                nsresult aStatus,
+                                const PRUnichar* aMessage)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
-                                    nsIRequest* aRequest,
-                                    uint32_t state)
+HTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
+                                  nsIRequest* aRequest,
+                                  uint32_t state)
 {
   NS_NOTREACHED("notification excluded in AddProgressListener(...)");
   return NS_OK;
 }
 
 NS_IMETHODIMP_(int32_t)
-nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl)
+HTMLFormElement::IndexOfControl(nsIFormControl* aControl)
 {
   int32_t index = 0;
   return mControls->IndexOfControl(aControl, &index) == NS_OK ? index : 0;
 }
 
 void
-nsHTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
-                                         nsIDOMHTMLInputElement* aRadio)
+HTMLFormElement::SetCurrentRadioButton(const nsAString& aName,
+                                       nsIDOMHTMLInputElement* aRadio)
 {
   mSelectedRadioButtons.Put(aName, aRadio);
 }
 
 nsIDOMHTMLInputElement*
-nsHTMLFormElement::GetCurrentRadioButton(const nsAString& aName)
+HTMLFormElement::GetCurrentRadioButton(const nsAString& aName)
 {
   return mSelectedRadioButtons.GetWeak(aName);
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::GetNextRadioButton(const nsAString& aName,
-                                      const bool aPrevious,
-                                      nsIDOMHTMLInputElement*  aFocusedRadio,
-                                      nsIDOMHTMLInputElement** aRadioOut)
+HTMLFormElement::GetNextRadioButton(const nsAString& aName,
+                                    const bool aPrevious,
+                                    nsIDOMHTMLInputElement*  aFocusedRadio,
+                                    nsIDOMHTMLInputElement** aRadioOut)
 {
   // Return the radio button relative to the focused radio button.
   // If no radio is focused, get the radio relative to the selected one.
   *aRadioOut = nullptr;
 
   nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
   if (aFocusedRadio) {
     currentRadio = aFocusedRadio;
@@ -2135,19 +2198,19 @@ nsHTMLFormElement::GetNextRadioButton(co
     radio->GetDisabled(&disabled);
   } while (disabled && radio != currentRadio);
 
   NS_IF_ADDREF(*aRadioOut = radio);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElement::WalkRadioGroup(const nsAString& aName,
-                                  nsIRadioVisitor* aVisitor,
-                                  bool aFlushContent)
+HTMLFormElement::WalkRadioGroup(const nsAString& aName,
+                                nsIRadioVisitor* aVisitor,
+                                bool aFlushContent)
 {
   if (aName.IsEmpty()) {
     //
     // XXX If the name is empty, it's not stored in the control list.  There
     // *must* be a more efficient way to do this.
     //
     nsCOMPtr<nsIFormControl> control;
     uint32_t len = GetElementCount();
@@ -2195,31 +2258,31 @@ nsHTMLFormElement::WalkRadioGroup(const 
         !aVisitor->Visit(formControl)) {
       break;
     }
   }
   return NS_OK;
 }
 
 void
-nsHTMLFormElement::AddToRadioGroup(const nsAString& aName,
-                                   nsIFormControl* aRadio)
+HTMLFormElement::AddToRadioGroup(const nsAString& aName,
+                                 nsIFormControl* aRadio)
 {
   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
   NS_ASSERTION(element, "radio controls have to be content elements!");
 
   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
     mRequiredRadioButtonCounts.Put(aName,
                                    mRequiredRadioButtonCounts.Get(aName)+1);
   }
 }
 
 void
-nsHTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
-                                        nsIFormControl* aRadio)
+HTMLFormElement::RemoveFromRadioGroup(const nsAString& aName,
+                                      nsIFormControl* aRadio)
 {
   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
   NS_ASSERTION(element, "radio controls have to be content elements!");
 
   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
     uint32_t requiredNb = mRequiredRadioButtonCounts.Get(aName);
     NS_ASSERTION(requiredNb >= 1,
                  "At least one radio button has to be required!");
@@ -2228,24 +2291,24 @@ nsHTMLFormElement::RemoveFromRadioGroup(
       mRequiredRadioButtonCounts.Remove(aName);
     } else {
       mRequiredRadioButtonCounts.Put(aName, requiredNb-1);
     }
   }
 }
 
 uint32_t
-nsHTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const
+HTMLFormElement::GetRequiredRadioCount(const nsAString& aName) const
 {
   return mRequiredRadioButtonCounts.Get(aName);
 }
 
 void
-nsHTMLFormElement::RadioRequiredChanged(const nsAString& aName,
-                                        nsIFormControl* aRadio)
+HTMLFormElement::RadioRequiredChanged(const nsAString& aName,
+                                      nsIFormControl* aRadio)
 {
   nsCOMPtr<nsIContent> element = do_QueryInterface(aRadio);
   NS_ASSERTION(element, "radio controls have to be content elements!");
 
   if (element->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
     mRequiredRadioButtonCounts.Put(aName,
                                    mRequiredRadioButtonCounts.Get(aName)+1);
   } else {
@@ -2256,57 +2319,57 @@ nsHTMLFormElement::RadioRequiredChanged(
       mRequiredRadioButtonCounts.Remove(aName);
     } else {
       mRequiredRadioButtonCounts.Put(aName, requiredNb-1);
     }
   }
 }
 
 bool
-nsHTMLFormElement::GetValueMissingState(const nsAString& aName) const
+HTMLFormElement::GetValueMissingState(const nsAString& aName) const
 {
   return mValueMissingRadioGroups.Get(aName);
 }
 
 void
-nsHTMLFormElement::SetValueMissingState(const nsAString& aName, bool aValue)
+HTMLFormElement::SetValueMissingState(const nsAString& aName, bool aValue)
 {
   mValueMissingRadioGroups.Put(aName, aValue);
 }
 
 nsEventStates
-nsHTMLFormElement::IntrinsicState() const
+HTMLFormElement::IntrinsicState() const
 {
   nsEventStates state = nsGenericHTMLElement::IntrinsicState();
 
   if (mInvalidElementsCount) {
     state |= NS_EVENT_STATE_INVALID;
   } else {
       state |= NS_EVENT_STATE_VALID;
   }
 
   return state;
 }
 
 void
-nsHTMLFormElement::Clear()
+HTMLFormElement::Clear()
 {
   for (int32_t i = mImageElements.Length() - 1; i >= 0; i--) {
     mImageElements[i]->ClearForm(false);
   }
   mImageElements.Clear();
   mImageNameLookupTable.Clear();
   mPastNameLookupTable.Clear();
 }
 
 //----------------------------------------------------------------------
 // nsFormControlList implementation, this could go away if there were
 // a lightweight collection implementation somewhere
 
-nsFormControlList::nsFormControlList(nsHTMLFormElement* aForm) :
+nsFormControlList::nsFormControlList(HTMLFormElement* aForm) :
   mForm(aForm),
   // Initialize the elements list to have an initial capacity
   // of 8 to reduce allocations on small forms.
   mElements(8)
 {
   SetIsDOMBinding();
 }
 
@@ -2449,43 +2512,44 @@ nsFormControlList::NamedItemInternal(con
 {
   if (aFlushContent) {
     FlushPendingNotifications();
   }
 
   return mNameLookupTable.GetWeak(aName);
 }
 
-static nsresult
-AddElementToTableInternal(
+nsresult
+HTMLFormElement::AddElementToTableInternal(
   nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
-  nsIContent* aChild, const nsAString& aName, nsHTMLFormElement* aForm)
+  nsIContent* aChild, const nsAString& aName)
 {
   nsCOMPtr<nsISupports> supports;
   aTable.Get(aName, getter_AddRefs(supports));
 
   if (!supports) {
     // No entry found, add the element
     aTable.Put(aName, aChild);
+    ++mExpandoAndGeneration.generation;
   } else {
     // Found something in the hash, check its type
     nsCOMPtr<nsIContent> content = do_QueryInterface(supports);
 
     if (content) {
       // Check if the new content is the same as the one we found in the
       // hash, if it is then we leave it in the hash as it is, this will
       // happen if a form control has both a name and an id with the same
       // value
       if (content == aChild) {
         return NS_OK;
       }
 
       // Found an element, create a list, add the element to the list and put
       // the list in the hash
-      nsSimpleContentList *list = new nsSimpleContentList(aForm);
+      nsSimpleContentList *list = new nsSimpleContentList(this);
 
       // If an element has a @form, we can assume it *might* be able to not have
       // a parent and still be in the form.
       NS_ASSERTION(content->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
                    content->GetParent(), "Item in list without parent");
 
       // Determine the ordering between the new and old element.
       bool newFirst = nsContentUtils::PositionIsBefore(aChild, content);
@@ -2551,17 +2615,17 @@ AddElementToTableInternal(
 nsresult
 nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
                                      const nsAString& aName)
 {
   if (!ShouldBeInElements(aChild)) {
     return NS_OK;
   }
 
-  return AddElementToTableInternal(mNameLookupTable, aChild, aName, mForm);
+  return mForm->AddElementToTableInternal(mNameLookupTable, aChild, aName);
 }
 
 nsresult
 nsFormControlList::IndexOfControl(nsIFormControl* aControl,
                                   int32_t* aIndex)
 {
   // Note -- not a DOM method; callers should handle flushing themselves
   
@@ -2575,17 +2639,17 @@ nsFormControlList::IndexOfControl(nsIFor
 nsresult
 nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
                                           const nsAString& aName)
 {
   if (!ShouldBeInElements(aChild)) {
     return NS_OK;
   }
 
-  return RemoveElementFromTableInternal(mNameLookupTable, aChild, aName);
+  return mForm->RemoveElementFromTableInternal(mNameLookupTable, aChild, aName);
 }
 
 nsresult
 nsFormControlList::GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const
 {
 #ifdef DEBUG
   AssertDocumentOrder(mElements, mForm);
   AssertDocumentOrder(mNotInElements, mForm);
@@ -2701,58 +2765,66 @@ nsFormControlList::GetSupportedNames(nsT
   FlushPendingNotifications();
   // Just enumerate mNameLookupTable.  This won't guarantee order, but
   // that's OK, because the HTML5 spec doesn't define an order for
   // this enumeration.
   mNameLookupTable.EnumerateRead(CollectNames, &aNames);
 }
 
 nsresult
-nsHTMLFormElement::AddImageElement(HTMLImageElement* aChild)
+HTMLFormElement::AddImageElement(HTMLImageElement* aChild)
 {
   AddElementToList(mImageElements, aChild, this);
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild,
-                                          const nsAString& aName)
+HTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild,
+                                        const nsAString& aName)
 {
-  return AddElementToTableInternal(mImageNameLookupTable, aChild, aName, this);
+  return AddElementToTableInternal(mImageNameLookupTable, aChild, aName);
 }
 
 nsresult
-nsHTMLFormElement::RemoveImageElement(HTMLImageElement* aChild)
+HTMLFormElement::RemoveImageElement(HTMLImageElement* aChild)
 {
   uint32_t index = mImageElements.IndexOf(aChild);
   NS_ENSURE_STATE(index != mImageElements.NoIndex);
 
   mImageElements.RemoveElementAt(index);
   return NS_OK;
 }
 
 nsresult
-nsHTMLFormElement::RemoveImageElementFromTable(HTMLImageElement* aElement,
-                                               const nsAString& aName,
-                                               RemoveElementReason aRemoveReason)
+HTMLFormElement::RemoveImageElementFromTable(HTMLImageElement* aElement,
+                                             const nsAString& aName,
+                                             RemoveElementReason aRemoveReason)
 {
   // If the element is being removed from the form, we have to remove it from
   // the past names map.
   if (aRemoveReason == ElementRemoved) {
     mPastNameLookupTable.Enumerate(RemovePastNames, aElement);
   }
 
   return RemoveElementFromTableInternal(mImageNameLookupTable, aElement, aName);
 }
 
 void
-nsHTMLFormElement::AddToPastNamesMap(const nsAString& aName,
-                                     nsISupports* aChild)
+HTMLFormElement::AddToPastNamesMap(const nsAString& aName,
+                                   nsISupports* aChild)
 {
   // If candidates contains exactly one node. Add a mapping from name to the
   // node in candidates in the form element's past names map, replacing the
   // previous entry with the same name, if any.
   nsCOMPtr<nsIContent> node = do_QueryInterface(aChild);
   if (node) {
     mPastNameLookupTable.Put(aName, aChild);
   }
 }
-
+ 
+JSObject*
+HTMLFormElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return HTMLFormElementBinding::Wrap(aCx, aScope, this);
+}
+
+} // namespace dom
+} // namespace mozilla
rename from content/html/content/src/nsHTMLFormElement.h
rename to content/html/content/src/HTMLFormElement.h
--- a/content/html/content/src/nsHTMLFormElement.h
+++ b/content/html/content/src/HTMLFormElement.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHTMLFormElement_h__
-#define nsHTMLFormElement_h__
+#ifndef mozilla_dom_HTMLFormElement_h
+#define mozilla_dom_HTMLFormElement_h
 
 #include "mozilla/Attributes.h"
 #include "nsCOMPtr.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsFormSubmission.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLFormElement.h"
@@ -23,35 +23,41 @@
 
 // Including 'windows.h' will #define GetClassInfo to something else.
 #ifdef XP_WIN
 #ifdef GetClassInfo
 #undef GetClassInfo
 #endif
 #endif
 
-class nsFormControlList;
 class nsIMutableArray;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 class HTMLImageElement;
 }
 }
 
-class nsHTMLFormElement : public nsGenericHTMLElement,
-                          public nsIDOMHTMLFormElement,
-                          public nsIWebProgressListener,
-                          public nsIForm,
-                          public nsIRadioGroupContainer
+namespace mozilla {
+namespace dom {
+
+class nsFormControlList;
+
+class HTMLFormElement : public nsGenericHTMLElement,
+                        public nsIDOMHTMLFormElement,
+                        public nsIWebProgressListener,
+                        public nsIForm,
+                        public nsIRadioGroupContainer
 {
+  friend class nsFormControlList;
+
 public:
-  nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo);
-  virtual ~nsHTMLFormElement();
+  HTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo);
+  virtual ~HTMLFormElement();
 
   nsresult Init();
 
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE_TO_NSINODE
@@ -122,18 +128,18 @@ public:
   /**
    * Forget all information about the current submission (and the fact that we
    * are currently submitting at all).
    */
   void ForgetCurrentSubmission();
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLFormElement,
-                                           nsGenericHTMLElement)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(HTMLFormElement,
+                                                         nsGenericHTMLElement)
 
   /**
    * Remove an element from this form's list of elements
    *
    * @param aElement the element to remove
    * @param aUpdateValidity If true, updates the form validity.
    * @return NS_OK if the element was successfully removed.
    */
@@ -306,82 +312,182 @@ public:
 
   /**
    * Implements form[name]. Returns form controls in this form with the correct
    * value of the name attribute.
    */
   already_AddRefed<nsISupports>
   FindNamedItem(const nsAString& aName, nsWrapperCache** aCache);
 
+  // WebIDL
+
+  void GetAcceptCharset(DOMString& aValue)
+  {
+    GetHTMLAttr(nsGkAtoms::acceptcharset, aValue);
+  }
+
+  void SetAcceptCharset(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::acceptcharset, aValue, aRv);
+  }
+
+  // XPCOM GetAction() is OK
+  void SetAction(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::action, aValue, aRv);
+  }
+
+  // XPCOM GetAutocomplete() is OK
+  void SetAutocomplete(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::autocomplete, aValue, aRv);
+  }
+
+  // XPCOM GetEnctype() is OK
+  void SetEnctype(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::enctype, aValue, aRv);
+  }
+
+  // XPCOM GetEncoding() is OK
+  void SetEncoding(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetEnctype(aValue, aRv);
+  }
+
+  // XPCOM GetMethod() is OK
+  void SetMethod(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::method, aValue, aRv);
+  }
+
+  void GetName(DOMString& aValue)
+  {
+    GetHTMLAttr(nsGkAtoms::name, aValue);
+  }
+
+  void SetName(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::name, aValue, aRv);
+  }
+
+  bool NoValidate() const
+  {
+    return GetBoolAttr(nsGkAtoms::novalidate);
+  }
+
+  void SetNoValidate(bool aValue, ErrorResult& aRv)
+  {
+    SetHTMLBoolAttr(nsGkAtoms::novalidate, aValue, aRv);
+  }
+
+  void GetTarget(DOMString& aValue)
+  {
+    GetHTMLAttr(nsGkAtoms::target, aValue);
+  }
+
+  void SetTarget(const nsAString& aValue, ErrorResult& aRv)
+  {
+    SetHTMLAttr(nsGkAtoms::target, aValue, aRv);
+  }
+
+  // it's only out-of-line because the class definition is not available in the
+  // header
+  nsIHTMLCollection* Elements();
+
+  int32_t Length();
+
+  void Submit(ErrorResult& aRv);
+
+  // XPCOM Reset() is OK
+
+  bool CheckValidity()
+  {
+    return CheckFormValidity(nullptr);
+  }
+
+  Element*
+  IndexedGetter(uint32_t aIndex, bool &aFound);
+
+  already_AddRefed<nsISupports>
+  NamedGetter(const nsAString& aName, bool &aFound);
+
+  void GetSupportedNames(nsTArray<nsString >& aRetval);
+
+  js::ExpandoAndGeneration mExpandoAndGeneration;
+
 protected:
+  virtual JSObject* WrapNode(JSContext* aCx,
+                             JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
   void PostPasswordEvent();
   void EventHandled() { mFormPasswordEvent = nullptr; }
 
   class FormPasswordEvent : public nsAsyncDOMEvent
   {
   public:
-    FormPasswordEvent(nsHTMLFormElement* aEventNode,
+    FormPasswordEvent(HTMLFormElement* aEventNode,
                       const nsAString& aEventType)
       : nsAsyncDOMEvent(aEventNode, aEventType, true, true)
     {}
 
     NS_IMETHOD Run() MOZ_OVERRIDE
     {
-      static_cast<nsHTMLFormElement*>(mEventNode.get())->EventHandled();
+      static_cast<HTMLFormElement*>(mEventNode.get())->EventHandled();
       return nsAsyncDOMEvent::Run();
     }
   };
 
   nsRefPtr<FormPasswordEvent> mFormPasswordEvent;
 
   class RemoveElementRunnable;
   friend class RemoveElementRunnable;
 
   class RemoveElementRunnable : public nsRunnable {
   public:
-    RemoveElementRunnable(nsHTMLFormElement* aForm)
+    RemoveElementRunnable(HTMLFormElement* aForm)
       : mForm(aForm)
     {}
 
     NS_IMETHOD Run() MOZ_OVERRIDE {
       mForm->HandleDefaultSubmitRemoval();
       return NS_OK;
     }
 
   private:
-    nsRefPtr<nsHTMLFormElement> mForm;
+    nsRefPtr<HTMLFormElement> mForm;
   };
 
   nsresult DoSubmitOrReset(nsEvent* aEvent,
                            int32_t aMessage);
   nsresult DoReset();
 
   // Async callback to handle removal of our default submit
   void HandleDefaultSubmitRemoval();
 
   //
   // Submit Helpers
   //
   //
   /**
-   * Attempt to submit (submission might be deferred) 
+   * Attempt to submit (submission might be deferred)
    * (called by DoSubmitOrReset)
    *
    * @param aPresContext the presentation context
    * @param aEvent the DOM event that was passed to us for the submit
    */
   nsresult DoSubmit(nsEvent* aEvent);
 
   /**
    * Prepare the submission object (called by DoSubmit)
    *
    * @param aFormSubmission the submission object
    * @param aEvent the DOM event that was passed to us for the submit
    */
-  nsresult BuildSubmission(nsFormSubmission** aFormSubmission, 
+  nsresult BuildSubmission(nsFormSubmission** aFormSubmission,
                            nsEvent* aEvent);
   /**
    * Perform the submission (called by DoSubmit and FlushPendingSubmission)
    *
    * @param aFormSubmission the submission object
    */
   nsresult SubmitSubmission(nsFormSubmission* aFormSubmission);
 
@@ -421,16 +527,26 @@ protected:
   bool CheckFormValidity(nsIMutableArray* aInvalidElements) const;
 
   // Clear the mImageNameLookupTable and mImageElements.
   void Clear();
 
   // Insert a element into the past names map.
   void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild);
 
+  nsresult
+  AddElementToTableInternal(
+    nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
+    nsIContent* aChild, const nsAString& aName);
+
+  nsresult
+  RemoveElementFromTableInternal(
+    nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
+    nsIContent* aChild, const nsAString& aName);
+
 public:
   /**
    * Flush a possible pending submission. If there was a scripted submission
    * triggered by a button or image, the submission was defered. This method
    * forces the pending submission to be submitted. (happens when the handler
    * returns false or there is an action/target change in the script)
    */
   void FlushPendingSubmission();
@@ -514,9 +630,12 @@ protected:
 
 protected:
   /** Detection of first form to notify observers */
   static bool gFirstFormSubmitted;
   /** Detection of first password input to initialize the password manager */
   static bool gPasswordManagerInitialized;
 };
 
-#endif // nsHTMLFormElement_h__
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_HTMLFormElement_h
--- a/content/html/content/src/HTMLImageElement.cpp
+++ b/content/html/content/src/HTMLImageElement.cpp
@@ -20,53 +20,33 @@
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsIFrame.h"
 #include "nsNodeInfoManager.h"
 #include "nsGUIEvent.h"
 #include "nsContentPolicyUtils.h"
 #include "nsIDOMWindow.h"
 #include "nsFocusManager.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 
 #include "imgIContainer.h"
 #include "imgILoader.h"
 #include "imgINotificationObserver.h"
 #include "imgRequestProxy.h"
 
 #include "nsILoadGroup.h"
 
 #include "nsRuleData.h"
 
 #include "nsIDOMHTMLMapElement.h"
 #include "nsEventDispatcher.h"
 
 #include "nsLayoutUtils.h"
 
-nsGenericHTMLElement*
-NS_NewHTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                       mozilla::dom::FromParser aFromParser)
-{
-  /*
-   * HTMLImageElement's will be created without a nsINodeInfo passed in
-   * if someone says "var img = new Image();" in JavaScript, in a case like
-   * that we request the nsINodeInfo from the document's nodeinfo list.
-   */
-  nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
-  if (!nodeInfo) {
-    nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller();
-    NS_ENSURE_TRUE(doc, nullptr);
-
-    nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::img, nullptr,
-                                                   kNameSpaceID_XHTML,
-                                                   nsIDOMNode::ELEMENT_NODE);
-  }
-
-  return new mozilla::dom::HTMLImageElement(nodeInfo.forget());
-}
+NS_IMPL_NS_NEW_HTML_ELEMENT(Image)
 
 namespace mozilla {
 namespace dom {
 
 HTMLImageElement::HTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nullptr)
 {
@@ -307,17 +287,17 @@ HTMLImageElement::BeforeSetAttr(int32_t 
   if (aNameSpaceID == kNameSpaceID_None && mForm &&
       (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
     // remove the image from the hashtable as needed
     nsAutoString tmp;
     GetAttr(kNameSpaceID_None, aName, tmp);
 
     if (!tmp.IsEmpty()) {
       mForm->RemoveImageElementFromTable(this, tmp,
-                                         nsHTMLFormElement::AttributeUpdated);
+                                         HTMLFormElement::AttributeUpdated);
     }
   }
 
   return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
                                              aValue, aNotify);
 }
 
 nsresult
@@ -669,17 +649,17 @@ HTMLImageElement::GetForm() const
 
 void
 HTMLImageElement::SetForm(nsIDOMHTMLFormElement* aForm)
 {
   NS_PRECONDITION(aForm, "Don't pass null here");
   NS_ASSERTION(!mForm,
                "We don't support switching from one non-null form to another.");
 
-  mForm = static_cast<nsHTMLFormElement*>(aForm);
+  mForm = static_cast<HTMLFormElement*>(aForm);
 }
 
 void
 HTMLImageElement::ClearForm(bool aRemoveFromForm)
 {
   NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM),
                "Form control should have had flag set correctly");
 
@@ -691,22 +671,22 @@ HTMLImageElement::ClearForm(bool aRemove
     nsAutoString nameVal, idVal;
     GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
     GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
 
     mForm->RemoveImageElement(this);
 
     if (!nameVal.IsEmpty()) {
       mForm->RemoveImageElementFromTable(this, nameVal,
-                                         nsHTMLFormElement::ElementRemoved);
+                                         HTMLFormElement::ElementRemoved);
     }
 
     if (!idVal.IsEmpty()) {
       mForm->RemoveImageElementFromTable(this, idVal,
-                                         nsHTMLFormElement::ElementRemoved);
+                                         HTMLFormElement::ElementRemoved);
     }
   }
 
   UnsetFlags(ADDED_TO_FORM);
   mForm = nullptr;
 }
 
 } // namespace dom
--- a/content/html/content/src/HTMLImageElement.h
+++ b/content/html/content/src/HTMLImageElement.h
@@ -192,15 +192,15 @@ protected:
                                  const nsAttrValueOrString* aValue,
                                  bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                                 const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
 
   // This is a weak reference that this element and the HTMLFormElement
   // cooperate in maintaining.
-  nsHTMLFormElement* mForm;
+  HTMLFormElement* mForm;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_HTMLImageElement_h */
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -2319,17 +2319,17 @@ HTMLInputElement::MaybeSubmitForm(nsPres
     shell->HandleDOMEventWithTarget(submitContent, &event, &status);
   } else if (mForm->HasSingleTextControl() &&
              (mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
               mForm->CheckValidFormSubmission())) {
     // TODO: removing this code and have the submit event sent by the form,
     // bug 592124.
     // If there's only one text control, just submit the form
     // Hold strong ref across the event
-    nsRefPtr<nsHTMLFormElement> form = mForm;
+    nsRefPtr<mozilla::dom::HTMLFormElement> form = mForm;
     nsFormEvent event(true, NS_FORM_SUBMIT);
     nsEventStatus status = nsEventStatus_eIgnore;
     shell->HandleDOMEventWithTarget(mForm, &event, &status);
   }
 
   return NS_OK;
 }
 
@@ -3160,17 +3160,17 @@ HTMLInputElement::PostHandleEvent(nsEven
             // form, see bug 592124.
             if (presShell && (event.message != NS_FORM_SUBMIT ||
                               mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
                               // We know the element is a submit control, if this check is moved,
                               // make sure formnovalidate is used only if it's a submit control.
                               HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) ||
                               mForm->CheckValidFormSubmission())) {
               // Hold a strong ref while dispatching
-              nsRefPtr<nsHTMLFormElement> form(mForm);
+              nsRefPtr<mozilla::dom::HTMLFormElement> form(mForm);
               presShell->HandleDOMEventWithTarget(mForm, &event, &status);
               aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
             }
           }
           break;
 
         default:
           break;
--- a/content/html/content/src/HTMLInputElement.h
+++ b/content/html/content/src/HTMLInputElement.h
@@ -12,17 +12,17 @@
 #include "nsIDOMHTMLInputElement.h"
 #include "nsITextControlElement.h"
 #include "nsIPhonetic.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsTextEditorState.h"
 #include "nsCOMPtr.h"
 #include "nsIConstraintValidation.h"
 #include "nsDOMFile.h"
-#include "nsHTMLFormElement.h" // for ShouldShowInvalidUI()
+#include "mozilla/dom/HTMLFormElement.h" // for ShouldShowInvalidUI()
 #include "nsIFile.h"
 #include "nsIFilePicker.h"
 #include "nsIContentPrefService2.h"
 #include "mozilla/Decimal.h"
 
 class nsDOMFileList;
 class nsIFilePicker;
 class nsIRadioGroupContainer;
--- a/content/html/content/src/HTMLLegendElement.cpp
+++ b/content/html/content/src/HTMLLegendElement.cpp
@@ -159,22 +159,22 @@ void
 HTMLLegendElement::PerformAccesskey(bool aKeyCausesActivation,
                                     bool aIsTrustedEvent)
 {
   // just use the same behaviour as the focus method
   ErrorResult rv;
   Focus(rv);
 }
 
-already_AddRefed<nsHTMLFormElement>
+already_AddRefed<HTMLFormElement>
 HTMLLegendElement::GetForm()
 {
   Element* form = GetFormElement();
   MOZ_ASSERT_IF(form, form->IsHTML(nsGkAtoms::form));
-  nsRefPtr<nsHTMLFormElement> ret = static_cast<nsHTMLFormElement*>(form);
+  nsRefPtr<HTMLFormElement> ret = static_cast<HTMLFormElement*>(form);
   return ret.forget();
 }
 
 JSObject*
 HTMLLegendElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return HTMLLegendElementBinding::Wrap(aCx, aScope, this);
 }
--- a/content/html/content/src/HTMLLegendElement.h
+++ b/content/html/content/src/HTMLLegendElement.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_HTMLLegendElement_h
 #define mozilla_dom_HTMLLegendElement_h
 
 #include "mozilla/Attributes.h"
 #include "nsIDOMHTMLLegendElement.h"
 #include "nsGenericHTMLElement.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLLegendElement : public nsGenericHTMLElement,
                           public nsIDOMHTMLLegendElement
 {
 public:
@@ -80,17 +80,17 @@ public:
   }
 
   virtual nsIDOMNode* AsDOMNode() MOZ_OVERRIDE { return this; }
 
   /**
    * WebIDL Interface
    */
 
-  already_AddRefed<nsHTMLFormElement> GetForm();
+  already_AddRefed<HTMLFormElement> GetForm();
 
   // The XPCOM GetAlign is OK for us
   void SetAlign(const nsAString& aAlign, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::align, aAlign, aError);
   }
 
   nsINode* GetParentObject() {
--- a/content/html/content/src/HTMLObjectElement.cpp
+++ b/content/html/content/src/HTMLObjectElement.cpp
@@ -75,26 +75,25 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_IN
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(HTMLObjectElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLObjectElement, Element)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLObjectElement)
   NS_HTML_CONTENT_INTERFACES(nsGenericHTMLFormElement)
-  NS_INTERFACE_TABLE_INHERITED11(HTMLObjectElement,
+  NS_INTERFACE_TABLE_INHERITED10(HTMLObjectElement,
                                  nsIDOMHTMLObjectElement,
                                  imgINotificationObserver,
                                  nsIRequestObserver,
                                  nsIStreamListener,
                                  nsIFrameLoaderOwner,
                                  nsIObjectLoadingContent,
                                  nsIImageLoadingContent,
                                  imgIOnloadBlocker,
-                                 nsIInterfaceRequestor,
                                  nsIChannelEventSink,
                                  nsIConstraintValidation)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
 NS_ELEMENT_INTERFACE_MAP_END
 
 NS_IMPL_ELEMENT_CLONE(HTMLObjectElement)
 
 // nsIConstraintValidation
--- a/content/html/content/src/HTMLOptionElement.cpp
+++ b/content/html/content/src/HTMLOptionElement.cpp
@@ -27,37 +27,17 @@
 #include "nsContentCreatorFunctions.h"
 #include "mozAutoDocUpdate.h"
 #include "nsTextNode.h"
 
 /**
  * Implementation of &lt;option&gt;
  */
 
-nsGenericHTMLElement*
-NS_NewHTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo,
-                        mozilla::dom::FromParser aFromParser)
-{
-  /*
-   * HTMLOptionElement's will be created without a nsINodeInfo passed in
-   * if someone says "var opt = new Option();" in JavaScript, in a case like
-   * that we request the nsINodeInfo from the document's nodeinfo list.
-   */
-  nsCOMPtr<nsINodeInfo> nodeInfo(aNodeInfo);
-  if (!nodeInfo) {
-    nsCOMPtr<nsIDocument> doc = nsContentUtils::GetDocumentFromCaller();
-    NS_ENSURE_TRUE(doc, nullptr);
-
-    nodeInfo = doc->NodeInfoManager()->GetNodeInfo(nsGkAtoms::option, nullptr,
-                                                   kNameSpaceID_XHTML,
-                                                   nsIDOMNode::ELEMENT_NODE);
-  }
-
-  return new mozilla::dom::HTMLOptionElement(nodeInfo.forget());
-}
+NS_IMPL_NS_NEW_HTML_ELEMENT(Option)
 
 namespace mozilla {
 namespace dom {
 
 HTMLOptionElement::HTMLOptionElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mSelectedChanged(false),
     mIsSelected(false),
@@ -94,17 +74,17 @@ NS_IMPL_ELEMENT_CLONE(HTMLOptionElement)
 
 NS_IMETHODIMP
 HTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   NS_IF_ADDREF(*aForm = GetForm());
   return NS_OK;
 }
 
-nsHTMLFormElement*
+mozilla::dom::HTMLFormElement*
 HTMLOptionElement::GetForm()
 {
   HTMLSelectElement* selectControl = GetSelect();
   return selectControl ? selectControl->GetForm() : nullptr;
 }
 
 void
 HTMLOptionElement::SetSelectedInternal(bool aValue, bool aNotify)
--- a/content/html/content/src/HTMLOptionElement.h
+++ b/content/html/content/src/HTMLOptionElement.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_HTMLOptionElement_h__
 #define mozilla_dom_HTMLOptionElement_h__
 
 #include "mozilla/Attributes.h"
 #include "nsGenericHTMLElement.h"
 #include "nsIDOMHTMLOptionElement.h"
 #include "nsIJSNativeInitializer.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 
 namespace mozilla {
 namespace dom {
 
 class HTMLSelectElement;
 
 class HTMLOptionElement : public nsGenericHTMLElement,
                           public nsIDOMHTMLOptionElement
@@ -86,17 +86,17 @@ public:
     return GetBoolAttr(nsGkAtoms::disabled);
   }
 
   void SetDisabled(bool aValue, ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::disabled, aValue, aRv);
   }
 
-  nsHTMLFormElement* GetForm();
+  HTMLFormElement* GetForm();
 
   // The XPCOM GetLabel is OK for us
   void SetLabel(const nsAString& aLabel, ErrorResult& aError)
   {
     SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
   }
 
   // The XPCOM DefaultSelected is OK for us
--- a/content/html/content/src/HTMLOutputElement.cpp
+++ b/content/html/content/src/HTMLOutputElement.cpp
@@ -5,17 +5,17 @@
 
 #include "mozilla/dom/HTMLOutputElement.h"
 
 #include "mozilla/dom/HTMLOutputElementBinding.h"
 #include "nsFormSubmission.h"
 #include "nsDOMSettableTokenList.h"
 #include "nsEventStates.h"
 #include "mozAutoDocUpdate.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Output)
 
 namespace mozilla {
 namespace dom {
 
 HTMLOutputElement::HTMLOutputElement(already_AddRefed<nsINodeInfo> aNodeInfo)
   : nsGenericHTMLFormElement(aNodeInfo)
--- a/content/html/content/src/HTMLSelectElement.h
+++ b/content/html/content/src/HTMLSelectElement.h
@@ -11,17 +11,17 @@
 #include "nsIConstraintValidation.h"
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/HTMLOptionsCollection.h"
 #include "mozilla/ErrorResult.h"
 #include "nsCheapSets.h"
 #include "nsCOMPtr.h"
 #include "nsError.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 
 class nsIDOMHTMLOptionElement;
 class nsISelectControlFrame;
 class nsPresState;
 
 namespace mozilla {
 namespace dom {
 
@@ -145,17 +145,17 @@ public:
   bool Disabled() const
   {
     return GetBoolAttr(nsGkAtoms::disabled);
   }
   void SetDisabled(bool aVal, ErrorResult& aRv)
   {
     SetHTMLBoolAttr(nsGkAtoms::disabled, aVal, aRv);
   }
-  nsHTMLFormElement* GetForm() const
+  HTMLFormElement* GetForm() const
   {
     return nsGenericHTMLFormElement::GetForm();
   }
   bool Multiple() const
   {
     return GetBoolAttr(nsGkAtoms::multiple);
   }
   void SetMultiple(bool aVal, ErrorResult& aRv)
--- a/content/html/content/src/HTMLSharedObjectElement.cpp
+++ b/content/html/content/src/HTMLSharedObjectElement.cpp
@@ -88,25 +88,24 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(HTMLSharedObjectElement, Element)
 NS_IMPL_RELEASE_INHERITED(HTMLSharedObjectElement, Element)
 
 NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLSharedObjectElement)
   NS_HTML_CONTENT_INTERFACES_AMBIGUOUS(nsGenericHTMLElement,
                                        nsIDOMHTMLAppletElement)
-  NS_INTERFACE_TABLE_INHERITED9(HTMLSharedObjectElement,
+  NS_INTERFACE_TABLE_INHERITED8(HTMLSharedObjectElement,
                                 nsIRequestObserver,
                                 nsIStreamListener,
                                 nsIFrameLoaderOwner,
                                 nsIObjectLoadingContent,
                                 imgINotificationObserver,
                                 nsIImageLoadingContent,
                                 imgIOnloadBlocker,
-                                nsIInterfaceRequestor,
                                 nsIChannelEventSink)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE
   NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLAppletElement, applet)
   NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLEmbedElement, embed)
 NS_ELEMENT_INTERFACE_MAP_END
 
 NS_IMPL_ELEMENT_CLONE(HTMLSharedObjectElement)
 
--- a/content/html/content/src/HTMLTextAreaElement.h
+++ b/content/html/content/src/HTMLTextAreaElement.h
@@ -11,17 +11,17 @@
 #include "nsIDOMHTMLTextAreaElement.h"
 #include "nsITextControlElement.h"
 #include "nsIDOMNSEditableElement.h"
 #include "nsCOMPtr.h"
 #include "nsGenericHTMLElement.h"
 #include "nsEventStates.h"
 #include "nsStubMutationObserver.h"
 #include "nsIConstraintValidation.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "nsGkAtoms.h"
 
 #include "nsTextEditorState.h"
 
 class nsFormSubmission;
 class nsIControllers;
 class nsIDocument;
 class nsPresContext;
--- a/content/html/content/src/moz.build
+++ b/content/html/content/src/moz.build
@@ -19,16 +19,17 @@ EXPORTS.mozilla.dom += [
     'HTMLBRElement.h',
     'HTMLBodyElement.h',
     'HTMLButtonElement.h',
     'HTMLDataElement.h',
     'HTMLDataListElement.h',
     'HTMLDivElement.h',
     'HTMLFieldSetElement.h',
     'HTMLFontElement.h',
+    'HTMLFormElement.h',
     'HTMLFrameElement.h',
     'HTMLFrameSetElement.h',
     'HTMLHRElement.h',
     'HTMLHeadingElement.h',
     'HTMLIFrameElement.h',
     'HTMLImageElement.h',
     'HTMLInputElement.h',
     'HTMLLIElement.h',
@@ -142,14 +143,14 @@ CPP_SOURCES += [
     'UndoManager.cpp',
     'ValidityState.cpp',
     'nsClientRect.cpp',
     'nsDOMStringMap.cpp',
     'nsFormSubmission.cpp',
     'nsGenericHTMLElement.cpp',
     'nsGenericHTMLFrameElement.cpp',
     'nsHTMLDNSPrefetch.cpp',
-    'nsHTMLFormElement.cpp',
+    'HTMLFormElement.cpp',
     'nsIConstraintValidation.cpp',
     'nsRadioVisitor.cpp',
     'nsTextEditorState.cpp',
 ]
 
--- a/content/html/content/src/nsDOMStringMap.cpp
+++ b/content/html/content/src/nsDOMStringMap.cpp
@@ -23,18 +23,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   // Check that mElement exists in case the unlink code is run more than once.
   if (tmp->mElement) {
     // Call back to element to null out weak reference to this object.
     tmp->mElement->ClearDataset();
     tmp->mElement->RemoveMutationObserver(tmp);
     tmp->mElement = nullptr;
   }
-  ++tmp->mExpandoAndGeneration.generation;
-  tmp->mExpandoAndGeneration.expando = JS::UndefinedValue();
+  tmp->mExpandoAndGeneration.Unlink();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMStringMap)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   if (tmp->PreservingWrapper()) {
     NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mExpandoAndGeneration.expando);
   }
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -59,17 +59,17 @@
 #include "nsGkAtoms.h"
 #include "nsEventStateManager.h"
 #include "nsIDOMEvent.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsITextControlFrame.h"
 #include "nsIForm.h"
 #include "nsIFormControl.h"
 #include "nsIDOMHTMLFormElement.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "nsFocusManager.h"
 #include "nsAttrValueOrString.h"
 
 #include "nsMutationEvent.h"
 #include "nsDOMStringMap.h"
 
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
@@ -646,18 +646,18 @@ nsGenericHTMLElement::UnbindFromTree(boo
     if (htmlDocument) {
       htmlDocument->ChangeContentEditableCount(this, -1);
     }
   }
 
   nsStyledElement::UnbindFromTree(aDeep, aNullParent);
 }
 
-nsHTMLFormElement*
-nsGenericHTMLElement::FindAncestorForm(nsHTMLFormElement* aCurrentForm)
+HTMLFormElement*
+nsGenericHTMLElement::FindAncestorForm(HTMLFormElement* aCurrentForm)
 {
   NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::form),
                "FindAncestorForm should not be called if @form is set!");
 
   // Make sure we don't end up finding a form that's anonymous from
   // our point of view.
   nsIContent* bindingParent = GetBindingParent();
 
@@ -672,17 +672,17 @@ nsGenericHTMLElement::FindAncestorForm(n
         // anonymous.  Check for this the hard way.
         for (nsIContent* child = this; child != content;
              child = child->GetParent()) {
           NS_ASSERTION(child->GetParent()->IndexOf(child) != -1,
                        "Walked too far?");
         }
       }
 #endif
-      return static_cast<nsHTMLFormElement*>(content);
+      return static_cast<HTMLFormElement*>(content);
     }
 
     nsIContent *prevContent = content;
     content = prevContent->GetParent();
 
     if (!content && aCurrentForm) {
       // We got to the root of the subtree we're in, and we're being removed
       // from the DOM (the only time we get into this method with a non-null
@@ -2153,17 +2153,17 @@ nsGenericHTMLFormElement::SaveSubtreeSta
 void
 nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
 {
   NS_PRECONDITION(aForm, "Don't pass null here");
   NS_ASSERTION(!mForm,
                "We don't support switching from one non-null form to another.");
 
   // keep a *weak* ref to the form here
-  mForm = static_cast<nsHTMLFormElement*>(aForm);
+  mForm = static_cast<HTMLFormElement*>(aForm);
 }
 
 void
 nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm)
 {
   NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM),
                "Form control should have had flag set correctly");
 
@@ -2175,22 +2175,22 @@ nsGenericHTMLFormElement::ClearForm(bool
     nsAutoString nameVal, idVal;
     GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
     GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
 
     mForm->RemoveElement(this, true);
 
     if (!nameVal.IsEmpty()) {
       mForm->RemoveElementFromTable(this, nameVal,
-                                    nsHTMLFormElement::ElementRemoved);
+                                    HTMLFormElement::ElementRemoved);
     }
 
     if (!idVal.IsEmpty()) {
       mForm->RemoveElementFromTable(this, idVal,
-                                    nsHTMLFormElement::ElementRemoved);
+                                    HTMLFormElement::ElementRemoved);
     }
   }
 
   UnsetFlags(ADDED_TO_FORM);
   mForm = nullptr;
 }
 
 Element*
@@ -2312,33 +2312,33 @@ nsGenericHTMLFormElement::BeforeSetAttr(
 
     // remove the control from the hashtable as needed
 
     if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
       GetAttr(kNameSpaceID_None, aName, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->RemoveElementFromTable(this, tmp,
-                                      nsHTMLFormElement::AttributeUpdated);
+                                      HTMLFormElement::AttributeUpdated);
       }
     }
 
     if (mForm && aName == nsGkAtoms::type) {
       GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->RemoveElementFromTable(this, tmp,
-                                      nsHTMLFormElement::AttributeUpdated);
+                                      HTMLFormElement::AttributeUpdated);
       }
 
       GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
 
       if (!tmp.IsEmpty()) {
         mForm->RemoveElementFromTable(this, tmp,
-                                      nsHTMLFormElement::AttributeUpdated);
+                                      HTMLFormElement::AttributeUpdated);
       }
 
       mForm->RemoveElement(this, false);
 
       // Removing the element from the form can make it not be the default
       // control anymore.  Go ahead and notify on that change, though we might
       // end up readding and becoming the default control again in
       // AfterSetAttr.
@@ -2650,17 +2650,17 @@ nsGenericHTMLFormElement::UpdateFormOwne
                   "aFormIdElement shouldn't be set if aBindToTree is true!");
 
   bool needStateUpdate = false;
   if (!aBindToTree) {
     needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
     ClearForm(true);
   }
 
-  nsHTMLFormElement *oldForm = mForm;
+  HTMLFormElement *oldForm = mForm;
 
   if (!mForm) {
     // If @form is set, we have to use that to find the form.
     nsAutoString formId;
     if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) {
       if (!formId.IsEmpty()) {
         Element* element = nullptr;
 
@@ -2673,17 +2673,17 @@ nsGenericHTMLFormElement::UpdateFormOwne
         NS_ASSERTION(GetCurrentDoc(), "The element should be in a document "
                                       "when UpdateFormOwner is called!");
         NS_ASSERTION(!GetCurrentDoc() ||
                      element == GetCurrentDoc()->GetElementById(formId),
                      "element should be equals to the current element "
                      "associated with the id in @form!");
 
         if (element && element->IsHTML(nsGkAtoms::form)) {
-          mForm = static_cast<nsHTMLFormElement*>(element);
+          mForm = static_cast<HTMLFormElement*>(element);
         }
       }
      } else {
       // We now have a parent, so we may have picked up an ancestor form.  Search
       // for it.  Note that if mForm is already set we don't want to do this,
       // because that means someone (probably the content sink) has already set
       // it to the right value.  Also note that even if being bound here didn't
       // change our parent, we still need to search, since our parent chain
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -28,23 +28,23 @@ class nsIDOMCSSStyleDeclaration;
 class nsIURI;
 class nsIFormControlFrame;
 class nsIForm;
 class nsPresState;
 class nsILayoutHistoryState;
 class nsIEditor;
 struct nsRect;
 struct nsSize;
-class nsHTMLFormElement;
 class nsIDOMHTMLMenuElement;
 class nsIDOMHTMLCollection;
 class nsDOMSettableTokenList;
 
 namespace mozilla {
 namespace dom{
+class HTMLFormElement;
 class HTMLPropertiesCollection;
 class HTMLMenuElement;
 }
 }
 
 typedef nsMappedAttributeElement nsGenericHTMLElementBase;
 
 /**
@@ -661,17 +661,18 @@ public:
    * Find an ancestor of this content node which is a form (could be null)
    * @param aCurrentForm the current form for this node.  If this is
    *        non-null, and no ancestor form is found, and the current form is in
    *        a connected subtree with the node, the current form will be
    *        returned.  This is needed to handle cases when HTML elements have a
    *        current form that they're not descendants of.
    * @note This method should not be called if the element has a form attribute.
    */
-  nsHTMLFormElement* FindAncestorForm(nsHTMLFormElement* aCurrentForm = nullptr);
+  mozilla::dom::HTMLFormElement*
+  FindAncestorForm(mozilla::dom::HTMLFormElement* aCurrentForm = nullptr);
 
   virtual void RecompileScriptEventListeners() MOZ_OVERRIDE;
 
   /**
    * See if the document being tested has nav-quirks mode enabled.
    * @param doc the document
    */
   static bool InNavQuirksMode(nsIDocument* aDoc);
@@ -1082,17 +1083,17 @@ public:
 
   nsINode* GetParentObject() const;
 
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
   virtual void SaveSubtreeState() MOZ_OVERRIDE;
 
   // nsIFormControl
   virtual mozilla::dom::Element* GetFormElement() MOZ_OVERRIDE;
-  nsHTMLFormElement* GetForm() const
+  mozilla::dom::HTMLFormElement* GetForm() const
   {
     return mForm;
   }
   virtual void SetForm(nsIDOMHTMLFormElement* aForm) MOZ_OVERRIDE;
   virtual void ClearForm(bool aRemoveFromForm) MOZ_OVERRIDE;
 
   nsresult GetForm(nsIDOMHTMLFormElement** aForm);
 
@@ -1216,17 +1217,17 @@ protected:
     eActiveWindow
   };
 
   // Get our focus state.  If this returns eInactiveWindow, it will set this
   // element as the focused element for that window.
   FocusTristate FocusState();
 
   /** The form that contains this control */
-  nsHTMLFormElement* mForm;
+  mozilla::dom::HTMLFormElement* mForm;
 
   /* This is a pointer to our closest fieldset parent if any */
   mozilla::dom::HTMLFieldSetElement* mFieldSet;
 };
 
 //----------------------------------------------------------------------
 
 /**
--- a/content/html/content/src/nsIConstraintValidation.cpp
+++ b/content/html/content/src/nsIConstraintValidation.cpp
@@ -2,17 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIConstraintValidation.h"
 
 #include "nsAString.h"
 #include "nsGenericHTMLElement.h"
-#include "nsHTMLFormElement.h"
+#include "mozilla/dom/HTMLFormElement.h"
 #include "mozilla/dom/ValidityState.h"
 #include "nsIFormControl.h"
 #include "nsContentUtils.h"
 
 const uint16_t nsIConstraintValidation::sContentSpecifiedMaxLengthMessage = 256;
 
 nsIConstraintValidation::nsIConstraintValidation()
   : mValidityBitField(0)
@@ -131,18 +131,18 @@ nsIConstraintValidation::SetValidityStat
     mValidityBitField &= ~aState;
   }
 
   // Inform the form element if our validity has changed.
   if (previousValidity != IsValid() && IsCandidateForConstraintValidation()) {
     nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this);
     NS_ASSERTION(formCtrl, "This interface should be used by form elements!");
 
-    nsHTMLFormElement* form =
-      static_cast<nsHTMLFormElement*>(formCtrl->GetFormElement());
+    mozilla::dom::HTMLFormElement* form =
+      static_cast<mozilla::dom::HTMLFormElement*>(formCtrl->GetFormElement());
     if (form) {
       form->UpdateValidity(IsValid());
     }
   }
 }
 
 void
 nsIConstraintValidation::SetCustomValidity(const nsAString& aError)
@@ -159,18 +159,18 @@ nsIConstraintValidation::SetBarredFromCo
   mBarredFromConstraintValidation = aBarred;
 
   // Inform the form element if our status regarding constraint validation
   // is going to change.
   if (!IsValid() && previousBarred != mBarredFromConstraintValidation) {
     nsCOMPtr<nsIFormControl> formCtrl = do_QueryInterface(this);
     NS_ASSERTION(formCtrl, "This interface should be used by form elements!");
 
-    nsHTMLFormElement* form =
-      static_cast<nsHTMLFormElement*>(formCtrl->GetFormElement());
+    mozilla::dom::HTMLFormElement* form =
+      static_cast<mozilla::dom::HTMLFormElement*>(formCtrl->GetFormElement());
     if (form) {
       // If the element is going to be barred from constraint validation,
       // we can inform the form that we are now valid.
       // Otherwise, we are now invalid.
       form->UpdateValidity(aBarred);
     }
   }
 }
--- a/content/html/content/test/reflect.js
+++ b/content/html/content/test/reflect.js
@@ -53,40 +53,28 @@ function reflectString(aParameters)
   element.setAttribute(contentAttr, null);
   is(element.getAttribute(contentAttr), "null",
      "null should have been stringified to 'null' for '" + contentAttr + "'");
   is(element[idlAttr], "null",
       "null should have been stringified to 'null' for '" + idlAttr + "'");
   element.removeAttribute(contentAttr);
 
   element[idlAttr] = null;
-  // TODO: remove this ugly hack when null stringification will work as expected.
-  var todoAttrs = {
-    form: [ "acceptCharset", "name", "target" ],
-  };
-  if (!(element.localName in todoAttrs) || todoAttrs[element.localName].indexOf(idlAttr) == -1) {
-    if (treatNullAs == "EmptyString") {
-      is(element.getAttribute(contentAttr), "",
-         "null should have been stringified to '' for '" + contentAttr + "'");
-      is(element[idlAttr], "",
-         "null should have been stringified to '' for '" + idlAttr + "'");
-    } else {
-      is(element.getAttribute(contentAttr), "null",
-         "null should have been stringified to 'null' for '" + contentAttr + "'");
-      is(element[idlAttr], "null",
-         "null should have been stringified to 'null' for '" + contentAttr + "'");
-    }
-    element.removeAttribute(contentAttr);
+  if (treatNullAs == "EmptyString") {
+    is(element.getAttribute(contentAttr), "",
+       "null should have been stringified to '' for '" + contentAttr + "'");
+    is(element[idlAttr], "",
+       "null should have been stringified to '' for '" + idlAttr + "'");
   } else {
-    todo_is(element.getAttribute(contentAttr), "null",
+    is(element.getAttribute(contentAttr), "null",
        "null should have been stringified to 'null' for '" + contentAttr + "'");
-    todo_is(element[idlAttr], "null",
+    is(element[idlAttr], "null",
        "null should have been stringified to 'null' for '" + contentAttr + "'");
-    element.removeAttribute(contentAttr);
   }
+  element.removeAttribute(contentAttr);
 
   // Tests various strings.
   var stringsToTest = [
     // [ test value, expected result ]
     [ "", "" ],
     [ "null", "null" ],
     [ "undefined", "undefined" ],
     [ "foo", "foo" ],
--- a/content/html/content/test/test_bug389797.html
+++ b/content/html/content/test/test_bug389797.html
@@ -67,18 +67,17 @@ function HTML_TAG(aTagName, aImplClass) 
     for (i = 0; i < arguments[3].length; ++i) {
       interfacesNonClassinfo[aTagName].push(arguments[3][i]);
     }
   }
 }
 
 const objectIfaces = [
     "imgINotificationObserver", "nsIRequestObserver", "nsIStreamListener",
-    "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIInterfaceRequestor",
-    "nsIChannelEventSink"
+    "nsIFrameLoaderOwner", "nsIObjectLoadingContent", "nsIChannelEventSink"
   ];
 
 var objectIfaces2 = [];
 for (var iface of objectIfaces) {
   objectIfaces2.push(iface);
 }
 objectIfaces2.push("nsIImageLoadingContent");
 
--- a/content/html/content/test/test_bug879319.html
+++ b/content/html/content/test/test_bug879319.html
@@ -47,19 +47,19 @@ ok("tmp1" in form.elements, "tmp1 is in 
 ok(!("tmp0" in form.elements), "tmp0 is not in form.elements");
 ok(!("foo0" in form.elements), "foo0 is not in form.elements");
 is(form.tmp0, input0, "Form.tmp0 == input0");
 is(form.tmp1, input0, "Form.tmp1 == input0");
 is(form.foo0, input0, "Form.foo0 is still here");
 
 input0.setAttribute("form", "");
 ok(!("foo0" in form.elements), "foo0 is not in form.elements");
-todo_is(form.foo0, undefined, "Form.foo0 should not still be here");
-todo_is(form.tmp0, undefined, "Form.tmp0 should not still be here");
-todo_is(form.tmp1, undefined, "Form.tmp1 should not still be here");
+is(form.foo0, undefined, "Form.foo0 should not still be here");
+is(form.tmp0, undefined, "Form.tmp0 should not still be here");
+is(form.tmp1, undefined, "Form.tmp1 should not still be here");
 
 var input1 = document.getElementById("input1");
 ok(input1, "input1 exists");
 is(form.foo1, input1, "Form.foo1 should exist");
 
 ok("foo1" in form.elements, "foo1 in form.elements");
 is(input1.form, form, "input1.form is form");
 
@@ -68,24 +68,25 @@ ok("foo0" in form.elements, "foo0 is in 
 is(form.foo0, input1, "Form.foo0 should be input1");
 is(form.foo1, input1, "Form.foo1 should be input1");
 
 var input2 = document.getElementById("input2");
 ok(input2, "input2 exists");
 is(form.foo2, input2, "Form.foo2 should exist");
 input2.parentNode.removeChild(input2);
 ok(!("foo2" in form.elements), "foo2 is not in form.elements");
-todo_is(form.foo2, undefined, "Form.foo2 should not longer be there");
+is(form.foo2, undefined, "Form.foo2 should not longer be there");
 
 var img0 = document.getElementById("img0");
 ok(img0, "img0 exists");
 is(form.bar0, img0, "Form.bar0 should exist");
 
 img0.setAttribute("name", "old_bar0");
+is(form.old_bar0, img0, "Form.bar0 is still here");
 is(form.bar0, img0, "Form.bar0 is still here");
 
 img0.parentNode.removeChild(img0);
-todo_is(form.bar0, undefined, "Form.bar0 should not be here");
+is(form.bar0, undefined, "Form.bar0 should not be here");
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/media/AudioNodeStream.h
+++ b/content/media/AudioNodeStream.h
@@ -103,16 +103,22 @@ public:
   bool IsAudioParamStream() const
   {
     return mAudioParamStream;
   }
   const OutputChunks& LastChunks() const
   {
     return mLastChunks;
   }
+  virtual bool MainThreadNeedsUpdates() const MOZ_OVERRIDE
+  {
+    // Only source and external streams need updates on the main thread.
+    return (mKind == MediaStreamGraph::SOURCE_STREAM && mFinished) ||
+           mKind == MediaStreamGraph::EXTERNAL_STREAM;
+  }
 
   // Any thread
   AudioNodeEngine* Engine() { return mEngine; }
   TrackRate SampleRate() const { return mSampleRate; }
 
 protected:
   void FinishOutput();
 
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -888,28 +888,34 @@ MediaStreamGraphImpl::PlayVideo(MediaStr
   }
 }
 
 void
 MediaStreamGraphImpl::PrepareUpdatesToMainThreadState(bool aFinalUpdate)
 {
   mMonitor.AssertCurrentThreadOwns();
 
+  mStreamUpdates.SetCapacity(mStreamUpdates.Length() + mStreams.Length());
   for (uint32_t i = 0; i < mStreams.Length(); ++i) {
     MediaStream* stream = mStreams[i];
+    if (!stream->MainThreadNeedsUpdates()) {
+      continue;
+    }
     StreamUpdate* update = mStreamUpdates.AppendElement();
     update->mGraphUpdateIndex = stream->mGraphUpdateIndices.GetAt(mCurrentTime);
     update->mStream = stream;
     update->mNextMainThreadCurrentTime =
       GraphTimeToStreamTime(stream, mCurrentTime);
     update->mNextMainThreadFinished =
       stream->mFinished &&
       StreamTimeToGraphTime(stream, stream->GetBufferEnd()) <= mCurrentTime;
   }
-  mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables);
+  if (!mPendingUpdateRunnables.IsEmpty()) {
+    mUpdateRunnables.MoveElementsFrom(mPendingUpdateRunnables);
+  }
 
   // Don't send the message to the main thread if it's not going to have
   // any work to do.
   if (aFinalUpdate ||
       !mUpdateRunnables.IsEmpty() ||
       !mCurrentTaskMessageQueue.IsEmpty() ||
       !mStreamUpdates.IsEmpty()) {
     EnsureStableStateEventPosted();
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -438,16 +438,22 @@ public:
   void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment);
 
   DOMMediaStream* GetWrapper()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only use DOMMediaStream on main thread");
     return mWrapper;
   }
 
+  // Return true if the main thread needs to observe updates from this stream.
+  virtual bool MainThreadNeedsUpdates() const
+  {
+    return true;
+  }
+
 protected:
   virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
   {
     mBufferStartTime += aBlockedTime;
     mGraphUpdateIndices.InsertTimeAtStart(aBlockedTime);
     mGraphUpdateIndices.AdvanceCurrentTime(aCurrentTime);
     mExplicitBlockerCount.AdvanceCurrentTime(aCurrentTime);
 
@@ -932,17 +938,17 @@ public:
    * tracks, whichever is greater.
    * TODO at some point we will probably need to add API to select
    * particular tracks of each input stream.
    */
   ProcessedMediaStream* CreateTrackUnionStream(DOMMediaStream* aWrapper);
   // Internal AudioNodeStreams can only pass their output to another
   // AudioNode, whereas external AudioNodeStreams can pass their output
   // to an nsAudioStream for playback.
-  enum AudioNodeStreamKind { INTERNAL_STREAM, EXTERNAL_STREAM };
+  enum AudioNodeStreamKind { SOURCE_STREAM, INTERNAL_STREAM, EXTERNAL_STREAM };
   /**
    * Create a stream that will process audio for an AudioNode.
    * Takes ownership of aEngine.  aSampleRate is the sampling rate used
    * for the stream.  If 0 is passed, the sampling rate of the engine's
    * node will get used.
    */
   AudioNodeStream* CreateAudioNodeStream(AudioNodeEngine* aEngine,
                                          AudioNodeStreamKind aKind,
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -159,17 +159,17 @@ CheckedInt64 UsecsToFrames(int64_t aUsec
 
 // Number of microseconds per second. 1e6.
 static const int64_t USECS_PER_S = 1000000;
 
 // Number of microseconds per millisecond.
 static const int64_t USECS_PER_MS = 1000;
 
 // Converts seconds to milliseconds.
-#define SECONDS_TO_MS(s) ((s) / PR_MSEC_PER_SEC)
+#define MS_TO_SECONDS(s) ((s) / PR_MSEC_PER_SEC)
 
 // The maximum height and width of the video. Used for
 // sanitizing the memory allocation of the RGB buffer.
 // The maximum resolution we anticipate encountering in the
 // wild is 2160p - 3840x2160 pixels.
 static const int32_t MAX_VIDEO_WIDTH = 4000;
 static const int32_t MAX_VIDEO_HEIGHT = 3000;
 
--- a/content/media/WebVTTLoadListener.cpp
+++ b/content/media/WebVTTLoadListener.cpp
@@ -155,17 +155,17 @@ WebVTTLoadListener::ParseChunk(nsIInputS
 
 void
 WebVTTLoadListener::OnParsedCue(webvtt_cue* aCue)
 {
   const char* text = webvtt_string_text(&aCue->body);
 
   nsRefPtr<TextTrackCue> textTrackCue =
     new TextTrackCue(mElement->OwnerDoc()->GetParentObject(),
-                     SECONDS_TO_MS(aCue->from), SECONDS_TO_MS(aCue->until),
+                     MS_TO_SECONDS(aCue->from), MS_TO_SECONDS(aCue->until),
                      NS_ConvertUTF8toUTF16(text), mElement,
                      aCue->node_head);
 
   text = webvtt_string_text(&aCue->id);
   textTrackCue->SetId(NS_ConvertUTF8toUTF16(text));
 
   textTrackCue->SetSnapToLines(aCue->snap_to_lines);
   textTrackCue->SetSize(aCue->settings.size);
--- a/content/media/webaudio/AudioBufferSourceNode.cpp
+++ b/content/media/webaudio/AudioBufferSourceNode.cpp
@@ -433,17 +433,17 @@ AudioBufferSourceNode::AudioBufferSource
   , mDuration(std::numeric_limits<double>::min())
   , mPlaybackRate(new AudioParam(this, SendPlaybackRateToStream, 1.0f))
   , mLoop(false)
   , mStartCalled(false)
   , mStopped(false)
 {
   mStream = aContext->Graph()->CreateAudioNodeStream(
       new AudioBufferSourceNodeEngine(this, aContext->Destination()),
-      MediaStreamGraph::INTERNAL_STREAM);
+      MediaStreamGraph::SOURCE_STREAM);
   mStream->AddMainThreadListener(this);
 }
 
 AudioBufferSourceNode::~AudioBufferSourceNode()
 {
   if (Context()) {
     Context()->UnregisterAudioBufferSourceNode(this);
   }
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -361,17 +361,17 @@ AudioContext::DecodeAudioData(const Arra
   // Failed type sniffing will be handled by AsyncDecodeMedia.
   nsAutoCString contentType;
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr,
                   aBuffer.Data(), aBuffer.Length(),
                   contentType);
 
   nsCOMPtr<DecodeErrorCallback> failureCallback;
   if (aFailureCallback.WasPassed()) {
-    failureCallback = aFailureCallback.Value().get();
+    failureCallback = &aFailureCallback.Value();
   }
   nsAutoPtr<WebAudioDecodeJob> job(
     new WebAudioDecodeJob(contentType, this,
                           &aSuccessCallback, failureCallback));
   mDecoder.AsyncDecodeMedia(contentType.get(),
                             aBuffer.Data(), aBuffer.Length(), *job);
   // Transfer the ownership to mDecodeJobs
   mDecodeJobs.AppendElement(job.forget());
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -114,33 +114,33 @@ nsXBLDocGlobalObject::doCheckAccess(JSCo
 
   nsresult rv = ssm->CheckPropertyAccess(cx, base, JS_GetClass(base)->name,
                                          id, accessType);
   return NS_SUCCEEDED(rv);
 }
 
 static JSBool
 nsXBLDocGlobalObject_getProperty(JSContext *cx, JSHandleObject obj,
-                                 JSHandleId id, JSMutableHandleValue vp)
+                                 JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   return nsXBLDocGlobalObject::
     doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
 }
 
 static JSBool
 nsXBLDocGlobalObject_setProperty(JSContext *cx, JSHandleObject obj,
-                                 JSHandleId id, JSBool strict, JSMutableHandleValue vp)
+                                 JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp)
 {
   return nsXBLDocGlobalObject::
     doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
 }
 
 static JSBool
 nsXBLDocGlobalObject_checkAccess(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                 JSAccessMode mode, JSMutableHandleValue vp)
+                                 JSAccessMode mode, JS::MutableHandle<JS::Value> vp)
 {
   uint32_t translated;
   if (mode & JSACC_WRITE) {
     translated = nsIXPCSecurityManager::ACCESS_SET_PROPERTY;
   } else {
     translated = nsIXPCSecurityManager::ACCESS_GET_PROPERTY;
   }
 
--- a/content/xbl/src/nsXBLMaybeCompiled.h
+++ b/content/xbl/src/nsXBLMaybeCompiled.h
@@ -60,26 +60,26 @@ private:
     // An pointer that represents the function before being compiled, with
     // BIT_UNCOMPILED set.
     uintptr_t mUncompiled;
 
     // The JS object for the compiled result.
     JSObject* mCompiled;
   };
 
-  friend class js::RootMethods<nsXBLMaybeCompiled<UncompiledT> >;
+  friend class js::GCMethods<nsXBLMaybeCompiled<UncompiledT> >;
 };
 
 /* Add support for JS::Heap<nsXBLMaybeCompiled>. */
 namespace js {
 
 template <class UncompiledT>
-struct RootMethods<nsXBLMaybeCompiled<UncompiledT> > : public RootMethods<JSObject *>
+struct GCMethods<nsXBLMaybeCompiled<UncompiledT> > : public GCMethods<JSObject *>
 {
-  typedef struct RootMethods<JSObject *> Base;
+  typedef struct GCMethods<JSObject *> Base;
 
   static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
 
   static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
   {
     return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
   }
 
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -12144,17 +12144,17 @@ nsDocShell::OnLinkClickSync(nsIContent *
   }
 
   if (!IsOKToLoadURI(aURI)) {
     return NS_OK;
   }
 
   // XXX When the linking node was HTMLFormElement, it is synchronous event.
   //     That is, the caller of this method is not |OnLinkClickEvent::Run()|
-  //     but |nsHTMLFormElement::SubmitSubmission(...)|.
+  //     but |HTMLFormElement::SubmitSubmission(...)|.
   if (nsGkAtoms::form == aContent->Tag() && ShouldBlockLoadingForBackButton()) {
     return NS_OK;
   }
 
   if (aContent->IsEditable()) {
     return NS_OK;
   }
 
--- a/dom/apps/src/OfflineCacheInstaller.jsm
+++ b/dom/apps/src/OfflineCacheInstaller.jsm
@@ -73,17 +73,17 @@ function storeCache(applicationCache, ur
       applicationCache.markEntry(url, itemType);
       cacheEntry.close();
     }
   });
 }
 
 function readFile(aFile, aCallback) {
   let channel = NetUtil.newChannel(aFile);
-  channel.contentType = "pain/text";
+  channel.contentType = "plain/text";
   NetUtil.asyncFetch(channel, function(aStream, aResult) {
     if (!Components.isSuccessCode(aResult)) {
       Cu.reportError("OfflineCacheInstaller: Could not read file " + aFile.path);
       if (aCallback)
         aCallback(null);
       return;
     }
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -521,17 +521,17 @@ static nsDOMClassInfoData sClassInfoData
 #undef MOZ_GENERATED_EVENT_LIST
 
   NS_DEFINE_CLASSINFO_DATA(DeviceAcceleration, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(DeviceRotationRate, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   // HTML element classes
-  NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, nsHTMLFormElementSH,
+  NS_DEFINE_CLASSINFO_DATA(HTMLFormElement, HTMLFormElementSH,
                            ELEMENT_SCRIPTABLE_FLAGS |
                            nsIXPCScriptable::WANT_GETPROPERTY |
                            nsIXPCScriptable::WANT_NEWENUMERATE)
 
   // CSS classes
   NS_DEFINE_CLASSINFO_DATA(CSSStyleRule, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CSSCharsetRule, nsDOMGenericSH,
@@ -2647,17 +2647,17 @@ static JSClass sGlobalScopePolluterClass
   JS_ConvertStub,
   nullptr
 };
 
 
 // static
 JSBool
 nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JSHandleObject obj,
-                                           JSHandleId id, JSMutableHandleValue vp)
+                                           JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   // Someone is accessing a element by referencing its name/id in the
   // global scope, do a security check to make sure that's ok.
 
   nsresult rv =
     sSecMan->CheckPropertyAccess(cx, ::JS_GetGlobalForObject(cx, obj),
                                  "Window", id,
                                  nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
@@ -2670,17 +2670,17 @@ nsWindowSH::GlobalScopePolluterGetProper
   }
 
   return JS_TRUE;
 }
 
 // Gets a subframe.
 static JSBool
 ChildWindowGetter(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                  JSMutableHandleValue vp)
+                  JS::MutableHandle<JS::Value> vp)
 {
   MOZ_ASSERT(JSID_IS_STRING(id));
   // Grab the native DOM window.
   vp.setUndefined();
   nsCOMPtr<nsISupports> winSupports =
     do_QueryInterface(nsDOMClassInfo::XPConnect()->GetNativeOfWrapper(cx, obj));
   if (!winSupports)
     return true;
@@ -3153,17 +3153,17 @@ static const IDBConstant sIDBConstants[]
   { IDBConstant::IDBRequest,     "LOADING",           "pending" },
   { IDBConstant::IDBRequest,     "DONE",              "done" },
   { IDBConstant::IDBTransaction, "READ_ONLY",         "readonly" },
   { IDBConstant::IDBTransaction, "READ_WRITE",        "readwrite" },
   { IDBConstant::IDBTransaction, "VERSION_CHANGE",    "versionchange" },
 };
 
 static JSBool
-IDBConstantGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+IDBConstantGetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   JSString *idstr = JSID_TO_STRING(id);
   unsigned index;
   for (index = 0; index < mozilla::ArrayLength(sIDBConstants); index++) {
     JSBool match;
     if (!JS_StringEqualsAscii(cx, idstr, sIDBConstants[index].name, &match)) {
       return JS_FALSE;
     }
@@ -4290,30 +4290,30 @@ LocationSetterGuts(JSContext *cx, JSObje
   NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
 
   return location->SetHref(depStr);
 }
 
 template<class Interface>
 static JSBool
 LocationSetter(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,
-               JSMutableHandleValue vp)
+               JS::MutableHandle<JS::Value> vp)
 {
   nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp.address());
   if (NS_FAILED(rv)) {
     xpc::Throw(cx, rv);
     return JS_FALSE;
   }
 
   return JS_TRUE;
 }
 
 static JSBool
 LocationSetterUnwrapper(JSContext *cx, JSHandleObject obj_, JSHandleId id, JSBool strict,
-                        JSMutableHandleValue vp)
+                        JS::MutableHandle<JS::Value> vp)
 {
   JS::RootedObject obj(cx, obj_);
 
   JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj);
   if (wrapped) {
     obj = wrapped;
   }
 
@@ -5696,17 +5696,17 @@ nsHTMLDocumentSH::GetDocumentAllNodeList
     return JS_FALSE;
   }
 
   return *nodeList != nullptr;
 }
 
 JSBool
 nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSHandleObject obj_,
-                                         JSHandleId id, JSMutableHandleValue vp)
+                                         JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   JS::Rooted<JSObject*> obj(cx, obj_);
 
   // document.all.item and .namedItem get their value in the
   // newResolve hook, so nothing to do for those properties here. And
   // we need to return early to prevent <div id="item"> from shadowing
   // document.all.item(), etc.
   if (nsDOMClassInfo::sItem_id == id || nsDOMClassInfo::sNamedItem_id == id) {
@@ -5886,63 +5886,63 @@ nsHTMLDocumentSH::CallToGetPropMapper(JS
 
   return ::JS_GetUCProperty(cx, self, chars, length, vp);
 }
 
 
 // HTMLFormElement helper
 
 NS_IMETHODIMP
-nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
-                                JSContext *cx, JSObject *aObj, jsid aId,
-                                uint32_t flags, JSObject **objp,
-                                bool *_retval)
+HTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
+                              JSContext *cx, JSObject *aObj, jsid aId,
+                              uint32_t flags, JSObject **objp,
+                              bool *_retval)
 {
   JS::Rooted<JSObject*> obj(cx, aObj);
   JS::Rooted<jsid> id(cx, aId);
   // For native wrappers, do not resolve random names on form
   if ((!(JSRESOLVE_ASSIGNING & flags)) && JSID_IS_STRING(id) &&
       (!ObjectIsNativeWrapper(cx, obj) ||
        xpc::WrapperFactory::XrayWrapperNotShadowing(obj, id))) {
     nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj));
 
     nsDependentJSString name(id);
     nsWrapperCache* cache;
     nsCOMPtr<nsISupports> result =
-      static_cast<nsHTMLFormElement*>(form.get())->FindNamedItem(name, &cache);
+      static_cast<HTMLFormElement*>(form.get())->FindNamedItem(name, &cache);
 
     if (result) {
       *_retval = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nullptr,
                                          nullptr, JSPROP_ENUMERATE);
 
       *objp = obj;
 
       return *_retval ? NS_OK : NS_ERROR_FAILURE;
     }
   }
 
   return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval);
 }
 
 
 NS_IMETHODIMP
-nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
-                                 JSContext *cx, JSObject *aObj, jsid aId,
-                                 jsval *vp, bool *_retval)
+HTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
+                               JSContext *cx, JSObject *aObj, jsid aId,
+                               jsval *vp, bool *_retval)
 {
   JS::Rooted<JSObject*> obj(cx, aObj);
   JS::Rooted<jsid> id(cx, aId);
   nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj));
 
   if (JSID_IS_STRING(id)) {
     // For native wrappers, do not get random names on form
     nsDependentJSString name(id);
     nsWrapperCache* cache;
     nsCOMPtr<nsISupports> result =
-      static_cast<nsHTMLFormElement*>(form.get())->FindNamedItem(name, &cache);
+      static_cast<HTMLFormElement*>(form.get())->FindNamedItem(name, &cache);
 
     if (result) {
       // Wrap result, result can be either an element or a list of
       // elements
       nsresult rv = WrapNative(cx, obj, result, cache, true, vp);
       return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
     }
   } else {
@@ -5960,20 +5960,20 @@ nsHTMLFormElementSH::GetProperty(nsIXPCo
       }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper,
-                                  JSContext *cx, JSObject *obj,
-                                  uint32_t enum_op, jsval *statep,
-                                  jsid *idp, bool *_retval)
+HTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper,
+                                JSContext *cx, JSObject *obj,
+                                uint32_t enum_op, jsval *statep,
+                                jsid *idp, bool *_retval)
 {
   switch (enum_op) {
   case JSENUMERATE_INIT:
   case JSENUMERATE_INIT_ALL:
     {
       nsCOMPtr<nsIForm> form(do_QueryWrappedNative(wrapper, obj));
 
       if (!form) {
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -367,17 +367,17 @@ public:
                       JSObject *obj) MOZ_OVERRIDE;
   NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                          JSObject * obj, JSObject * *_retval) MOZ_OVERRIDE;
 
   static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSHandleObject obj,
                                               JSHandleId id, unsigned flags,
                                               JS::MutableHandle<JSObject*> objp);
   static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSHandleObject obj,
-                                               JSHandleId id, JSMutableHandleValue vp);
+                                               JSHandleId id, JS::MutableHandle<JS::Value> vp);
   static JSBool InvalidateGlobalScopePolluter(JSContext *cx,
                                               JS::Handle<JSObject*> obj);
   static nsresult InstallGlobalScopePolluter(JSContext *cx,
                                              JS::Handle<JSObject*> obj);
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsWindowSH(aData);
   }
@@ -597,34 +597,34 @@ extern JSClass sHTMLDocumentAllClass;
 class nsHTMLDocumentSH
 {
 protected:
   static JSBool GetDocumentAllNodeList(JSContext *cx, JS::Handle<JSObject*> obj,
                                        nsDocument *doc,
                                        nsContentList **nodeList);
 public:
   static JSBool DocumentAllGetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                       JSMutableHandleValue vp);
+                                       JS::MutableHandle<JS::Value> vp);
   static JSBool DocumentAllNewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                       unsigned flags, JS::MutableHandle<JSObject*> objp);
   static void ReleaseDocument(JSFreeOp *fop, JSObject *obj);
   static JSBool CallToGetPropMapper(JSContext *cx, unsigned argc, jsval *vp);
 };
 
 
 // HTMLFormElement helper
 
-class nsHTMLFormElementSH : public nsElementSH
+class HTMLFormElementSH : public nsElementSH
 {
 protected:
-  nsHTMLFormElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData)
+  HTMLFormElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData)
   {
   }
 
-  virtual ~nsHTMLFormElementSH()
+  virtual ~HTMLFormElementSH()
   {
   }
 
 public:
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, uint32_t flags,
                         JSObject **objp, bool *_retval) MOZ_OVERRIDE;
   NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
@@ -633,17 +633,17 @@ public:
 
   NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper,
                           JSContext *cx, JSObject *obj,
                           uint32_t enum_op, jsval *statep,
                           jsid *idp, bool *_retval) MOZ_OVERRIDE;
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
-    return new nsHTMLFormElementSH(aData);
+    return new HTMLFormElementSH(aData);
   }
 };
 
 
 // Plugin helper
 
 class nsPluginSH : public nsNamedArraySH
 {
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -260,35 +260,43 @@ public:
   }
 
   template <class T1, class T2>
   void Construct(const T1 &t1, const T2 &t2)
   {
     mImpl.construct(t1, t2);
   }
 
-  const InternalType& Value() const
+  const T& Value() const
   {
     return mImpl.ref();
   }
 
+  // Return InternalType here so we can work with it usefully.
   InternalType& Value()
   {
     return mImpl.ref();
   }
 
+  // And an explicit way to get the InternalType even if we're const.
+  const InternalType& InternalValue() const
+  {
+    return mImpl.ref();
+  }
+
   // If we ever decide to add conversion operators for optional arrays
   // like the ones Nullable has, we'll need to ensure that Maybe<> has
   // the boolean before the actual data.
 
 private:
   // Forbid copy-construction and assignment
   Optional_base(const Optional_base& other) MOZ_DELETE;
   const Optional_base &operator=(const Optional_base &other) MOZ_DELETE;
 
+protected:
   Maybe<InternalType> mImpl;
 };
 
 template<typename T>
 class Optional : public Optional_base<T, T>
 {
 public:
   Optional() :
@@ -313,16 +321,30 @@ public:
     Optional_base<JS::Handle<T>, JS::Rooted<T> >()
   {
     this->Construct(cx);
   }
 
   Optional(JSContext* cx, const T& aValue) :
     Optional_base<JS::Handle<T>, JS::Rooted<T> >(cx, aValue)
   {}
+
+  // Override the const Value() to return the right thing so we're not
+  // returning references to temporaries.
+  JS::Handle<T> Value() const
+  {
+    return this->mImpl.ref();
+  }
+
+  // And we have to override the non-const one too, since we're
+  // shadowing the one on the superclass.
+  JS::Rooted<T>& Value()
+  {
+    return this->mImpl.ref();
+  }
 };
 
 // A specialization of Optional for JSObject* to make sure that when someone
 // calls Construct() on it we will pre-initialized the JSObject* to nullptr so
 // it can be traced safely.
 template<>
 class Optional<JSObject*> : public Optional_base<JSObject*, JSObject*>
 {
@@ -374,16 +396,61 @@ public:
 
   template <class T1>
   void Construct(const T1& t1)
   {
     Optional_base<JS::Value, JS::Value>::Construct(t1);
   }
 };
 
+// A specialization of Optional for NonNull that lets us get a T& from Value()
+template<typename U> class NonNull;
+template<typename T>
+class Optional<NonNull<T> > : public Optional_base<T, NonNull<T> >
+{
+public:
+  // We want our Value to actually return a non-const reference, even
+  // if we're const.  At least for things that are normally pointer
+  // types...
+  T& Value() const
+  {
+    return *this->mImpl.ref().get();
+  }
+
+  // And we have to override the non-const one too, since we're
+  // shadowing the one on the superclass.
+  NonNull<T>& Value()
+  {
+    return this->mImpl.ref();
+  }
+};
+
+// A specialization of Optional for OwningNonNull that lets us get a
+// T& from Value()
+template<typename U> class OwningNonNull;
+template<typename T>
+class Optional<OwningNonNull<T> > : public Optional_base<T, OwningNonNull<T> >
+{
+public:
+  // We want our Value to actually return a non-const reference, even
+  // if we're const.  At least for things that are normally pointer
+  // types...
+  T& Value() const
+  {
+    return *this->mImpl.ref().get();
+  }
+
+  // And we have to override the non-const one too, since we're
+  // shadowing the one on the superclass.
+  OwningNonNull<T>& Value()
+  {
+    return this->mImpl.ref();
+  }
+};
+
 // Specialization for strings.
 // XXXbz we can't pull in FakeDependentString here, because it depends on
 // internal strings.  So we just have to forward-declare it and reimplement its
 // ToAStringPtr.
 
 struct FakeDependentString;
 
 template<>
@@ -423,16 +490,82 @@ private:
   // Forbid copy-construction and assignment
   Optional(const Optional& other) MOZ_DELETE;
   const Optional &operator=(const Optional &other) MOZ_DELETE;
 
   bool mPassed;
   const nsAString* mStr;
 };
 
+template<class T>
+class NonNull
+{
+public:
+  NonNull()
+#ifdef DEBUG
+    : inited(false)
+#endif
+  {}
+
+  operator T&() {
+    MOZ_ASSERT(inited);
+    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
+    return *ptr;
+  }
+
+  operator const T&() const {
+    MOZ_ASSERT(inited);
+    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
+    return *ptr;
+  }
+
+  void operator=(T* t) {
+    ptr = t;
+    MOZ_ASSERT(ptr);
+#ifdef DEBUG
+    inited = true;
+#endif
+  }
+
+  template<typename U>
+  void operator=(U* t) {
+    ptr = t->ToAStringPtr();
+    MOZ_ASSERT(ptr);
+#ifdef DEBUG
+    inited = true;
+#endif
+  }
+
+  T** Slot() {
+#ifdef DEBUG
+    inited = true;
+#endif
+    return &ptr;
+  }
+
+  T* Ptr() {
+    MOZ_ASSERT(inited);
+    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
+    return ptr;
+  }
+
+  // Make us work with smart-ptr helpers that expect a get()
+  T* get() const {
+    MOZ_ASSERT(inited);
+    MOZ_ASSERT(ptr);
+    return ptr;
+  }
+
+protected:
+  T* ptr;
+#ifdef DEBUG
+  bool inited;
+#endif
+};
+
 // Class for representing sequences in arguments.  We use a non-auto array
 // because that allows us to use sequences of sequences and the like.  This
 // needs to be fallible because web content controls the length of the array,
 // and can easily try to create very large lengths.
 template<typename T>
 class Sequence : public FallibleTArray<T>
 {
 public:
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1750,17 +1750,17 @@ InterfaceHasInstance(JSContext* cx, JS::
     }
   }
 
   *bp = false;
   return true;
 }
 
 JSBool
-InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp,
                      JSBool* bp)
 {
   if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
   JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject());
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1346,75 +1346,16 @@ GetPropertyOnPrototype(JSContext* cx, JS
                        JS::Value* vp);
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        DOMProxyHandler* handler,
                        JS::Handle<jsid> id);
 
 template<class T>
-class NonNull
-{
-public:
-  NonNull()
-#ifdef DEBUG
-    : inited(false)
-#endif
-  {}
-
-  operator T&() {
-    MOZ_ASSERT(inited);
-    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
-    return *ptr;
-  }
-
-  operator const T&() const {
-    MOZ_ASSERT(inited);
-    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
-    return *ptr;
-  }
-
-  void operator=(T* t) {
-    ptr = t;
-    MOZ_ASSERT(ptr);
-#ifdef DEBUG
-    inited = true;
-#endif
-  }
-
-  template<typename U>
-  void operator=(U* t) {
-    ptr = t->ToAStringPtr();
-    MOZ_ASSERT(ptr);
-#ifdef DEBUG
-    inited = true;
-#endif
-  }
-
-  T* Ptr() {
-    MOZ_ASSERT(inited);
-    MOZ_ASSERT(ptr, "NonNull<T> was set to null");
-    return ptr;
-  }
-
-  // Make us work with smart-ptr helpers that expect a get()
-  T* get() const {
-    MOZ_ASSERT(inited);
-    MOZ_ASSERT(ptr);
-    return ptr;
-  }
-
-protected:
-  T* ptr;
-#ifdef DEBUG
-  bool inited;
-#endif
-};
-
-template<class T>
 class OwningNonNull
 {
 public:
   OwningNonNull()
 #ifdef DEBUG
     : inited(false)
 #endif
   {}
@@ -2024,17 +1965,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand
  *
  * instance should not be a security wrapper.
  */
 JSBool
 InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj,
                      JS::Handle<JSObject*> instance,
                      JSBool* bp);
 JSBool
-InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
+InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp,
                      JSBool* bp);
 
 // Helper for lenient getters/setters to report to console.  If this
 // returns false, we couldn't even get a global.
 bool
 ReportLenientThisUnwrappingFailure(JSContext* cx, JS::Handle<JSObject*> obj);
 
 inline JSObject*
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -324,17 +324,16 @@ DOMInterfaces = {
     'resultNotAddRefed': [ 'threshold', 'knee', 'ratio',
                            'reduction', 'attack', 'release' ],
     'binaryNames': {
         'release': 'getRelease'
     },
 },
 
 'Element': {
-    'hasXPConnectImpls': True,
     'resultNotAddRefed': [
         'classList', 'attributes', 'children', 'firstElementChild',
         'lastElementChild', 'previousElementSibling', 'nextElementSibling',
         'getAttributeNode', 'getAttributeNodeNS', 'querySelector'
     ]
 },
 
 'Event': [
@@ -453,17 +452,16 @@ DOMInterfaces = {
     'nativeType': 'nsHTMLDocument',
     'resultNotAddRefed': [ 'body', 'head', 'images', 'embeds', 'plugins',
                            'links', 'forms', 'scripts', 'anchors', 'applets' ],
     'implicitJSContext': [ 'open', 'write', 'writeln' ]
 },
 
 'HTMLElement': {
     'nativeType': 'nsGenericHTMLElement',
-    'hasXPConnectImpls': True,
     'resultNotAddRefed': [
         'itemType', 'itemRef', 'itemProp', 'properties', 'contextMenu', 'style',
         'offsetParent'
     ]
 },
 
 'HTMLEmbedElement': {
     'nativeType': 'mozilla::dom::HTMLSharedObjectElement'
@@ -687,17 +685,16 @@ DOMInterfaces = {
     'headerFile': 'nsDOMMutationObserver.h',
     'resultNotAddRefed': [ 'target', 'addedNodes', 'removedNodes',
                            'previousSibling', 'nextSibling' ]
 },
 
 'Node': {
     'nativeType': 'nsINode',
     'concrete': False,
-    'hasXPConnectImpls': True,
     'resultNotAddRefed': [ 'ownerDocument', 'parentNode', 'parentElement',
                            'childNodes', 'firstChild', 'lastChild',
                            'previousSibling', 'nextSibling', 'insertBefore',
                            'appendChild', 'replaceChild', 'removeChild',
                            'attributes' ]
 },
 
 'NodeIterator': {
@@ -1601,24 +1598,16 @@ def addExternalIface(iface, nativeType=N
     }
     if not nativeType is None:
         domInterface['nativeType'] = nativeType
     if not headerFile is None:
         domInterface['headerFile'] = headerFile
     domInterface['notflattened'] = notflattened
     DOMInterfaces[iface] = domInterface
 
-# If you add one of these, you need to make sure nsDOMQS.h has the relevant
-# macros added for it
-def addExternalHTMLElement(element):
-   nativeElement = 'ns' + element
-   addExternalIface(element, nativeType=nativeElement,
-                    headerFile=nativeElement + '.h')
-
-addExternalHTMLElement('HTMLFormElement')
 addExternalIface('ActivityOptions', nativeType='nsIDOMMozActivityOptions',
                  headerFile='nsIDOMActivityOptions.h')
 addExternalIface('Counter')
 addExternalIface('CSSRule')
 addExternalIface('DeviceAcceleration', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
 addExternalIface('DeviceRotationRate', headerFile='nsIDOMDeviceMotionEvent.h', notflattened=True)
 addExternalIface('mozIDOMApplication', nativeType='mozIDOMApplication', headerFile='nsIDOMApplicationRegistry.h')
 addExternalIface('CSSRuleList')
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -926,17 +926,17 @@ class CGAbstractClassHook(CGAbstractStat
         assert(False)
 
 class CGAddPropertyHook(CGAbstractClassHook):
     """
     A hook for addProperty, used to preserve our wrapper from GC.
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
-                Argument('JSHandleId', 'id'), Argument('JSMutableHandleValue', 'vp')]
+                Argument('JSHandleId', 'id'), Argument('JS::MutableHandle<JS::Value>', 'vp')]
         CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
                                      'JSBool', args)
 
     def generate_code(self):
         assert not self.descriptor.workers and self.descriptor.wrapperCache
         if self.descriptor.nativeOwnership == 'nsisupports':
             preserveArgs = "reinterpret_cast<nsISupports*>(self), self"
         else:
@@ -1183,17 +1183,17 @@ class CGNamedConstructors(CGThing):
         namedConstructors = CGWrapper(CGIndenter(namedConstructors),
                                       pre="static const NamedConstructor namedConstructors[] = {\n",
                                       post="\n};\n")
         return nativePropertyHooks + namedConstructors.define()
 
 class CGClassHasInstanceHook(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
-                Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')]
+                Argument('JS::MutableHandle<JS::Value>', 'vp'), Argument('JSBool*', 'bp')]
         CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
                                         'JSBool', args)
 
     def define(self):
         if not NeedsGeneratedHasInstance(self.descriptor):
             return ""
         return CGAbstractStaticMethod.define(self)
 
@@ -8012,17 +8012,17 @@ class CGDictionary(CGThing):
     def getMemberDefinition(self, memberInfo):
         member = memberInfo[0]
         declType = memberInfo[1].declType
         memberLoc = self.makeMemberName(member.identifier.name)
         if member.defaultValue:
             memberData = memberLoc
         else:
             # The data is inside the Optional<>
-            memberData = "%s.Value()" % memberLoc
+            memberData = "%s.InternalValue()" % memberLoc
 
         if self.workers:
             propDef = (
                 'JS_DefineProperty(cx, obj, "%s", temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
                 member.identifier.name)
         else:
             propDef = (
                 'JS_DefinePropertyById(cx, obj, %s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' %
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -104,38 +104,38 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPC
     nsJSObjWrapper::NP_GetProperty,
     nsJSObjWrapper::NP_SetProperty,
     nsJSObjWrapper::NP_RemoveProperty,
     nsJSObjWrapper::NP_Enumerate,
     nsJSObjWrapper::NP_Construct
   };
 
 static JSBool
-NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp);
 
 static JSBool
 NPObjWrapper_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded);
 
 static JSBool
 NPObjWrapper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,
-                         JSMutableHandleValue vp);
+                         JS::MutableHandle<JS::Value> vp);
 
 static JSBool
-NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp);
 
 static JSBool
 NPObjWrapper_newEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
                           JS::Value *statep, jsid *idp);
 
 static JSBool
 NPObjWrapper_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
                         JS::MutableHandle<JSObject*> objp);
 
 static JSBool
-NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp);
+NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp);
 
 static void
 NPObjWrapper_Finalize(JSFreeOp *fop, JSObject *obj);
 
 static JSBool
 NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static JSBool
@@ -166,17 +166,17 @@ JSClass sNPObjectJSWrapperClass =
 typedef struct NPObjectMemberPrivate {
     JSObject *npobjWrapper;
     JS::Value fieldValue;
     NPIdentifier methodName;
     NPP   npp;
 } NPObjectMemberPrivate;
 
 static JSBool
-NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp);
+NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp);
 
 static void
 NPObjectMember_Finalize(JSFreeOp *fop, JSObject *obj);
 
 static JSBool
 NPObjectMember_Call(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static void
@@ -1103,17 +1103,17 @@ GetNPObject(JSContext *cx, JSObject *obj
 
   return (NPObject *)::JS_GetPrivate(obj);
 }
 
 
 // Does not actually add a property because this is always followed by a
 // SetProperty call.
 static JSBool
-NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+NPObjWrapper_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
@@ -1178,17 +1178,17 @@ NPObjWrapper_DelProperty(JSContext *cx, 
   if (!npobj->_class->removeProperty(npobj, identifier))
     *succeeded = false;
 
   return ReportExceptionIfPending(cx);
 }
 
 static JSBool
 NPObjWrapper_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict,
-                         JSMutableHandleValue vp)
+                         JS::MutableHandle<JS::Value> vp)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->setProperty) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
@@ -1237,17 +1237,17 @@ NPObjWrapper_SetProperty(JSContext *cx, 
 
     return JS_FALSE;
   }
 
   return JS_TRUE;
 }
 
 static JSBool
-NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+NPObjWrapper_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp)
 {
   NPObject *npobj = GetNPObject(cx, obj);
 
   if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
       !npobj->_class->hasMethod || !npobj->_class->getProperty) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
@@ -1601,17 +1601,17 @@ NPObjWrapper_NewResolve(JSContext *cx, J
     return fnc != nullptr;
   }
 
   // no property or method
   return JS_TRUE;
 }
 
 static JSBool
-NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType hint, JSMutableHandleValue vp)
+NPObjWrapper_Convert(JSContext *cx, JSHandleObject obj, JSType hint, JS::MutableHandle<JS::Value> vp)
 {
   JS_ASSERT(hint == JSTYPE_NUMBER || hint == JSTYPE_STRING || hint == JSTYPE_VOID);
 
   // Plugins do not simply use JS_ConvertStub, and the default [[DefaultValue]]
   // behavior, because that behavior involves calling toString or valueOf on
   // objects which weren't designed to accommodate this.  Usually this wouldn't
   // be a problem, because the absence of either property, or the presence of
   // either property with a value that isn't callable, will cause that property
@@ -2021,17 +2021,17 @@ CreateNPObjectMember(NPP npp, JSContext 
   memberPrivate->npp = npp;
 
   ::JS_RemoveValueRoot(cx, vp);
 
   return JS_TRUE;
 }
 
 static JSBool
-NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp)
+NPObjectMember_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp)
 {
   NPObjectMemberPrivate *memberPrivate =
     (NPObjectMemberPrivate *)::JS_GetInstancePrivate(cx, obj,
                                                      &sNPObjectMemberClass,
                                                      nullptr);
   if (!memberPrivate) {
     NS_ERROR("no Ambiguous Member Private data!");
     return JS_FALSE;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -287,16 +287,17 @@ nsPluginHost::nsPluginHost()
 
   Preferences::AddStrongObserver(this, "plugin.disable");
   Preferences::AddStrongObserver(this, "plugins.click_to_play");
 
   nsCOMPtr<nsIObserverService> obsService =
     mozilla::services::GetObserverService();
   if (obsService) {
     obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+    obsService->AddObserver(this, "blocklist-updated", false);
 #ifdef MOZ_WIDGET_ANDROID
     obsService->AddObserver(this, "application-foreground", false);
     obsService->AddObserver(this, "application-background", false);
 #endif
   }
 
 #ifdef PLUGIN_LOGGING
   nsPluginLogging::gNPNLog = PR_NewLogModule(NPN_LOG_NAME);
@@ -1063,27 +1064,22 @@ nsPluginHost::GetStateForType(const nsAC
 
 nsresult
 nsPluginHost::GetBlocklistStateForType(const char *aMimeType, uint32_t *aState)
 {
   nsPluginTag *plugin = FindPluginForType(aMimeType, true);
   if (!plugin) {
     plugin = FindPluginForType(aMimeType, false);
   }
-  if (plugin) {
-    nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
-    if (blocklist) {
-      // The EmptyString()s are so we use the currently running application
-      // and toolkit versions
-      return blocklist->GetPluginBlocklistState(plugin, EmptyString(),
-                                                EmptyString(), aState);
-    }
+  if (!plugin) {
+    return NS_ERROR_FAILURE;
   }
 
-  return NS_ERROR_FAILURE;
+  *aState = plugin->GetBlocklistState();
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType, nsACString &aPermissionString)
 {
   aPermissionString.Truncate();
   uint32_t blocklistState;
   nsresult rv = GetBlocklistStateForType(aMimeType.Data(), &blocklistState);
@@ -1926,35 +1922,27 @@ nsresult nsPluginHost::ScanPluginsDirect
 
       pluginTag = new nsPluginTag(&info);
       pluginFile.FreePluginInfo(info);
       if (!pluginTag)
         return NS_ERROR_OUT_OF_MEMORY;
 
       pluginTag->mLibrary = library;
       pluginTag->mLastModifiedTime = fileModTime;
-
-      nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
-      if (blocklist) {
-        uint32_t state;
-        rv = blocklist->GetPluginBlocklistState(pluginTag, EmptyString(),
-                                                EmptyString(), &state);
-
-        if (NS_SUCCEEDED(rv)) {
-          // If the blocklist says it is risky and we have never seen this
-          // plugin before, then disable it.
-          // If the blocklist says this is an outdated plugin, warn about
-          // outdated plugins.
-          if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) {
-             pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED);
-          }
-          if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) {
-             warnOutdated = true;
-          }
-        }
+      uint32_t state = pluginTag->GetBlocklistState();
+
+      // If the blocklist says it is risky and we have never seen this
+      // plugin before, then disable it.
+      // If the blocklist says this is an outdated plugin, warn about
+      // outdated plugins.
+      if (state == nsIBlocklistService::STATE_SOFTBLOCKED && !seenBefore) {
+        pluginTag->SetEnabledState(nsIPluginTag::STATE_DISABLED);
+      }
+      if (state == nsIBlocklistService::STATE_OUTDATED && !seenBefore) {
+        warnOutdated = true;
       }
 
       // Plugin unloading is tag-based. If we created a new tag and loaded
       // the library in the process then we want to attempt to unload it here.
       // Only do this if the pref is set for aggressive unloading.
       if (UnloadPluginsASAP()) {
         pluginTag->TryUnloadPlugin(false);
       }
@@ -3141,44 +3129,51 @@ nsresult nsPluginHost::NewPluginStreamLi
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
                                     const char *aTopic,
                                     const PRUnichar *someData)
 {
-  if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
+  if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
     OnShutdown();
     UnloadPlugins();
     sInst->Release();
   }
-  if (!nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
+  if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
     mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
     mPluginsClickToPlay = Preferences::GetBool("plugins.click_to_play", false);
     // Unload or load plugins as needed
     if (mPluginsDisabled) {
       UnloadPlugins();
     } else {
       LoadPlugins();
     }
   }
+  if (!strcmp("blocklist-updated", aTopic)) {
+    nsPluginTag* plugin = mPlugins;
+    while (plugin) {
+      plugin->InvalidateBlocklistState();
+      plugin = plugin->mNext;
+    }
+  }
 #ifdef MOZ_WIDGET_ANDROID
-  if (!nsCRT::strcmp("application-background", aTopic)) {
+  if (!strcmp("application-background", aTopic)) {
     for(uint32_t i = 0; i < mInstances.Length(); i++) {
       mInstances[i]->NotifyForeground(false);
     }
   }
-  if (!nsCRT::strcmp("application-foreground", aTopic)) {
+  if (!strcmp("application-foreground", aTopic)) {
     for(uint32_t i = 0; i < mInstances.Length(); i++) {
       if (mInstances[i]->IsOnScreen())
         mInstances[i]->NotifyForeground(true);
     }
   }
-  if (!nsCRT::strcmp("memory-pressure", aTopic)) {
+  if (!strcmp("memory-pressure", aTopic)) {
     for(uint32_t i = 0; i < mInstances.Length(); i++) {
       mInstances[i]->MemoryPressure();
     }
   }
 #endif
   return NS_OK;
 }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -75,31 +75,35 @@ nsPluginTag::nsPluginTag(nsPluginTag* aP
     mExtensions(aPluginTag->mExtensions),
     mLibrary(nullptr),
     mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
     mIsFlashPlugin(aPluginTag->mIsFlashPlugin),
     mFileName(aPluginTag->mFileName),
     mFullPath(aPluginTag->mFullPath),
     mVersion(aPluginTag->mVersion),
     mLastModifiedTime(0),
-    mNiceFileName()
+    mNiceFileName(),
+    mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+    mCachedBlocklistStateValid(false)
 {
 }
 
 nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
   : mName(aPluginInfo->fName),
     mDescription(aPluginInfo->fDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aPluginInfo->fFileName),
     mFullPath(aPluginInfo->fFullPath),
     mVersion(aPluginInfo->fVersion),
     mLastModifiedTime(0),
-    mNiceFileName()
+    mNiceFileName(),
+    mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+    mCachedBlocklistStateValid(false)
 {
   InitMime(aPluginInfo->fMimeTypeArray,
            aPluginInfo->fMimeDescriptionArray,
            aPluginInfo->fExtensionArray,
            aPluginInfo->fVariantCount);
   EnsureMembersAreUTF8();
 }
 
@@ -118,17 +122,19 @@ nsPluginTag::nsPluginTag(const char* aNa
     mDescription(aDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aFileName),
     mFullPath(aFullPath),
     mVersion(aVersion),
     mLastModifiedTime(aLastModifiedTime),
-    mNiceFileName()
+    mNiceFileName(),
+    mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
+    mCachedBlocklistStateValid(false)
 {
   InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
            static_cast<uint32_t>(aVariants));
   if (!aArgsAreUTF8)
     EnsureMembersAreUTF8();
 }
 
 nsPluginTag::~nsPluginTag()
@@ -533,8 +539,40 @@ nsCString nsPluginTag::GetNiceFileName()
 }
 
 void nsPluginTag::ImportFlagsToPrefs(uint32_t flags)
 {
   if (!(flags & NS_PLUGIN_FLAG_ENABLED)) {
     SetPluginState(ePluginState_Disabled);
   }
 }
+
+uint32_t
+nsPluginTag::GetBlocklistState()
+{
+  if (mCachedBlocklistStateValid) {
+    return mCachedBlocklistState;
+  }
+
+  nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
+  if (!blocklist) {
+    return nsIBlocklistService::STATE_NOT_BLOCKED;
+  }
+
+  // The EmptyString()s are so we use the currently running application
+  // and toolkit versions
+  uint32_t state;
+  if (NS_FAILED(blocklist->GetPluginBlocklistState(this, EmptyString(),
+                                                   EmptyString(), &state))) {
+    return nsIBlocklistService::STATE_NOT_BLOCKED;
+  }
+
+  MOZ_ASSERT(state <= UINT16_MAX);
+  mCachedBlocklistState = (uint16_t) state;
+  mCachedBlocklistStateValid = true;
+  return state;
+}
+
+void
+nsPluginTag::InvalidateBlocklistState()
+{
+  mCachedBlocklistStateValid = false;
+}
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -80,18 +80,24 @@ public:
   nsRefPtr<nsNPAPIPlugin> mPlugin;
   bool          mIsJavaPlugin;
   bool          mIsFlashPlugin;
   nsCString     mFileName; // UTF-8
   nsCString     mFullPath; // UTF-8
   nsCString     mVersion;  // UTF-8
   int64_t       mLastModifiedTime;
   nsCOMPtr<nsITimer> mUnloadTimer;
+
+  uint32_t      GetBlocklistState();
+  void          InvalidateBlocklistState();
+
 private:
   nsCString     mNiceFileName; // UTF-8
+  uint16_t      mCachedBlocklistState;
+  bool          mCachedBlocklistStateValid;
 
   void InitMime(const char* const* aMimeTypes,
                 const char* const* aMimeDescriptions,
                 const char* const* aExtensions,
                 uint32_t aVariantCount);
   nsresult EnsureMembersAreUTF8();
 };
 
--- a/dom/src/notification/Notification.cpp
+++ b/dom/src/notification/Notification.cpp
@@ -377,17 +377,17 @@ Notification::RequestPermission(const Gl
   if (!sop) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
   }
   nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
 
   NotificationPermissionCallback* permissionCallback = nullptr;
   if (aCallback.WasPassed()) {
-    permissionCallback = aCallback.Value().get();
+    permissionCallback = &aCallback.Value();
   }
   nsCOMPtr<nsIRunnable> request =
     new NotificationPermissionRequest(principal, window, permissionCallback);
 
   NS_DispatchToMainThread(request);
 }
 
 NotificationPermission
--- a/dom/webidl/FormData.webidl
+++ b/dom/webidl/FormData.webidl
@@ -2,15 +2,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * The origin of this IDL file is
  * http://xhr.spec.whatwg.org
  */
 
-interface HTMLFormElement;
-
 [Constructor(optional HTMLFormElement form)]
 interface FormData {
   void append(DOMString name, Blob value, optional DOMString filename);
   void append(DOMString name, DOMString value);
-};
\ No newline at end of file
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/HTMLFormElement.webidl
@@ -0,0 +1,48 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * http://www.whatwg.org/specs/web-apps/current-work/#htmlformelement
+ *
+ * © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
+ * Opera Software ASA. You are granted a license to use, reproduce
+ * and create derivative works of this document.
+ */
+
+[OverrideBuiltins]
+interface HTMLFormElement : HTMLElement {
+           [Pure, SetterThrows]
+           attribute DOMString acceptCharset;
+           [Pure, SetterThrows]
+           attribute DOMString action;
+           [Pure, SetterThrows]
+           attribute DOMString autocomplete;
+           [Pure, SetterThrows]
+           attribute DOMString enctype;
+           [Pure, SetterThrows]
+           attribute DOMString encoding;
+           [Pure, SetterThrows]
+           attribute DOMString method;
+           [Pure, SetterThrows]
+           attribute DOMString name;
+           [Pure, SetterThrows]
+           attribute boolean noValidate;
+           [Pure, SetterThrows]
+           attribute DOMString target;
+
+  [Constant]
+  readonly attribute HTMLCollection elements;
+  [Pure]
+  readonly attribute long length;
+
+  getter Element (unsigned long index);
+  // TODO this should be: getter (RadioNodeList or HTMLInputElement or HTMLImageElement) (DOMString name);
+  getter nsISupports (DOMString name);
+
+  [Throws]
+  void submit();
+  void reset();
+  boolean checkValidity();
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -104,16 +104,17 @@ webidl_files = \
   HTMLDirectoryElement.webidl \
   HTMLDivElement.webidl \
   HTMLDListElement.webidl \
   HTMLDocument.webidl \
   HTMLElement.webidl \
   HTMLEmbedElement.webidl \
   HTMLFieldSetElement.webidl \
   HTMLFontElement.webidl \
+  HTMLFormElement.webidl \
   HTMLFrameElement.webidl \
   HTMLFrameSetElement.webidl \
   HTMLHeadElement.webidl \
   HTMLHeadingElement.webidl \
   HTMLHRElement.webidl \
   HTMLHtmlElement.webidl \
   HTMLIFrameElement.webidl \
   HTMLImageElement.webidl \
--- a/dom/workers/Events.cpp
+++ b/dom/workers/Events.cpp
@@ -215,33 +215,33 @@ private:
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
     delete GetJSPrivateSafeish<Event>(aObj);
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
 
     int32_t slot = JSID_TO_INT(aIdval);
 
     const char* name = sProperties[slot - SLOT_FIRST].name;
     if (!GetInstancePrivate(aCx, aObj, name)) {
       return false;
     }
 
     aVp.set(JS_GetReservedSlot(aObj, slot));
     return true;
   }
 
   static JSBool
-  GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JSMutableHandleValue aVp)
+  GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(idval));
     JS_ASSERT(JSID_TO_INT(idval) >= CAPTURING_PHASE &&
               JSID_TO_INT(idval) <= BUBBLING_PHASE);
 
     aVp.set(INT_TO_JSVAL(JSID_TO_INT(idval)));
     return true;
   }
@@ -500,17 +500,17 @@ private:
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
     MessageEvent* priv = GetJSPrivateSafeish<MessageEvent>(aObj);
     delete priv;
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
 
     int32_t slot = JSID_TO_INT(aIdval);
 
     JS_ASSERT(slot >= SLOT_data && slot < SLOT_COUNT);
 
     const char* name = sProperties[slot - SLOT_FIRST].name;
@@ -707,17 +707,17 @@ private:
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(IsThisClass(JS_GetClass(aObj)));
     delete GetJSPrivateSafeish<ErrorEvent>(aObj);
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
 
     int32_t slot = JSID_TO_INT(aIdval);
 
     JS_ASSERT(slot >= SLOT_message && slot < SLOT_COUNT);
 
     const char* name = sProperties[slot - SLOT_FIRST].name;
@@ -886,17 +886,17 @@ private:
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == &sClass);
     delete GetJSPrivateSafeish<ProgressEvent>(aObj);
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
 
     int32_t slot = JSID_TO_INT(aIdval);
 
     JS_ASSERT(slot >= SLOT_lengthComputable && slot < SLOT_COUNT);
 
     const char* name = sProperties[slot - SLOT_FIRST].name;
--- a/dom/workers/Exceptions.cpp
+++ b/dom/workers/Exceptions.cpp
@@ -121,17 +121,17 @@ private:
       return false;
     }
 
     JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(out));
     return true;
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
 
     int32_t slot = JSID_TO_INT(aIdval);
 
     JSClass* classPtr = JS_GetClass(aObj);
 
     if (classPtr != &sClass || !GetJSPrivateSafeish<DOMException>(aObj)) {
@@ -141,17 +141,17 @@ private:
       return false;
     }
 
     aVp.set(JS_GetReservedSlot(aObj, slot));
     return true;
   }
 
   static JSBool
-  GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JSMutableHandleValue aVp)
+  GetConstant(JSContext* aCx, JSHandleObject aObj, JSHandleId idval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(idval));
     aVp.set(INT_TO_JSVAL(JSID_TO_INT(idval)));
     return true;
   }
 };
 
 JSClass DOMException::sClass = {
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -108,17 +108,17 @@ private:
   {
     JS_ASSERT(JS_GetClass(aObj) == &sClass);
 
     nsIDOMBlob* blob = GetPrivate(aObj);
     NS_IF_RELEASE(blob);
   }
 
   static JSBool
-  GetSize(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetSize(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "size");
     if (!blob) {
       return false;
     }
 
     uint64_t size;
     if (NS_FAILED(blob->GetSize(&size))) {
@@ -127,17 +127,17 @@ private:
     }
 
     aVp.set(JS_NumberValue(double(size)));
 
     return true;
   }
 
   static JSBool
-  GetType(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetType(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "type");
     if (!blob) {
       return false;
     }
 
     nsString type;
     if (NS_FAILED(blob->GetType(type))) {
@@ -297,17 +297,17 @@ private:
   {
     JS_ASSERT(JS_GetClass(aObj) == &sClass);
 
     nsIDOMFile* file = GetPrivate(aObj);
     NS_IF_RELEASE(file);
   }
 
   static JSBool
-  GetMozFullPath(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetMozFullPath(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "mozFullPath");
     if (!file) {
       return false;
     }
 
     nsString fullPath;
 
@@ -323,17 +323,17 @@ private:
       return false;
     }
 
     aVp.set(STRING_TO_JSVAL(jsFullPath));
     return true;
   }
 
   static JSBool
-  GetName(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetName(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "name");
     if (!file) {
       return false;
     }
 
     nsString name;
     if (NS_FAILED(file->GetName(name))) {
@@ -345,17 +345,17 @@ private:
       return false;
     }
 
     aVp.set(STRING_TO_JSVAL(jsName));
     return true;
   }
 
   static JSBool
-  GetLastModifiedDate(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetLastModifiedDate(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "lastModifiedDate");
     if (!file) {
       return false;
     }
 
     JS::Rooted<JS::Value> value(aCx);
     if (NS_FAILED(file->GetLastModifiedDate(aCx, value.address()))) {
--- a/dom/workers/ImageData.cpp
+++ b/dom/workers/ImageData.cpp
@@ -110,17 +110,17 @@ private:
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
     delete static_cast<ImageData*>(JS_GetPrivate(aObj));
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr != &sClass) {
       JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                            JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
                            classPtr->name);
       return false;
     }
--- a/dom/workers/Location.cpp
+++ b/dom/workers/Location.cpp
@@ -124,17 +124,17 @@ private:
 
     jsval href = JS_GetReservedSlot(obj, SLOT_href);
 
     JS_SET_RVAL(aCx, aVp, href);
     return true;
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr != &sClass) {
       JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                            JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
                            classPtr->name);
       return false;
     }
--- a/dom/workers/Navigator.cpp
+++ b/dom/workers/Navigator.cpp
@@ -112,17 +112,17 @@ private:
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == &sClass);
     delete static_cast<Navigator*>(JS_GetPrivate(aObj));
   }
 
   static JSBool
-  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetProperty(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr != &sClass) {
       JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                            JSMSG_INCOMPATIBLE_PROTO, sClass.name, "GetProperty",
                            classPtr->name);
       return false;
     }
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -170,17 +170,17 @@ protected:
 private:
   // No instance of this class should ever be created so these are explicitly
   // left without an implementation to prevent linking in case someone tries to
   // make one.
   Worker();
   ~Worker();
 
   static JSBool
-  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
     if (!worker) {
       return !JS_IsExceptionPending(aCx);
@@ -195,17 +195,17 @@ private:
     }
 
     aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL);
     return true;
   }
 
   static JSBool
   SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict,
-                   JSMutableHandleValue aVp)
+                   JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerPrivate* worker = GetInstancePrivate(aCx, aObj, name);
     if (!worker) {
       return !JS_IsExceptionPending(aCx);
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -137,17 +137,17 @@ protected:
   virtual void
   _finalize(JSFreeOp* aFop) MOZ_OVERRIDE
   {
     EventTarget::_finalize(aFop);
   }
 
 private:
   static JSBool
-  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
@@ -164,17 +164,17 @@ private:
     }
 
     aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL);
     return true;
   }
 
   static JSBool
   SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict,
-                   JSMutableHandleValue aVp)
+                   JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
@@ -204,28 +204,28 @@ private:
   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
                          sClass.name);
     return false;
   }
 
   static JSBool
-  GetSelf(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetSelf(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     if (!GetInstancePrivate(aCx, aObj, "self")) {
       return false;
     }
 
     aVp.set(OBJECT_TO_JSVAL(aObj));
     return true;
   }
 
   static JSBool
-  GetLocation(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetLocation(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     WorkerGlobalScope* scope =
       GetInstancePrivate(aCx, aObj, sProperties[SLOT_location].name);
     if (!scope) {
       return false;
     }
 
     if (JSVAL_IS_VOID(scope->mSlots[SLOT_location])) {
@@ -304,17 +304,17 @@ private:
         !JS_CallFunctionName(aCx, event, "preventDefault", 0, NULL, rval.address())) {
       return false;
     }
 
     return true;
   }
 
   static JSBool
-  GetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     const char* name = sEventStrings[STRING_onerror];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
     }
 
     ErrorResult rv;
@@ -336,17 +336,17 @@ private:
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(aVp));
 
     return true;
   }
 
   static JSBool
   SetOnErrorListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval,
-                     JSBool aStrict, JSMutableHandleValue aVp)
+                     JSBool aStrict, JS::MutableHandle<JS::Value> aVp)
   {
     const char* name = sEventStrings[STRING_onerror];
     WorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
     }
 
     if (JSVAL_IS_PRIMITIVE(aVp)) {
@@ -378,17 +378,17 @@ private:
       JS_ReportError(aCx, "Failed to set event listener!");
       return false;
     }
 
     return true;
   }
 
   static JSBool
-  GetNavigator(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetNavigator(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     WorkerGlobalScope* scope =
       GetInstancePrivate(aCx, aObj, sProperties[SLOT_navigator].name);
     if (!scope) {
       return false;
     }
 
     if (JSVAL_IS_VOID(scope->mSlots[SLOT_navigator])) {
@@ -727,17 +727,17 @@ protected:
     MOZ_COUNT_DTOR(mozilla::dom::workers::DedicatedWorkerGlobalScope);
   }
 
 private:
   using EventTarget::GetEventListener;
   using EventTarget::SetEventListener;
 
   static JSBool
-  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSMutableHandleValue aVp)
+  GetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
@@ -754,17 +754,17 @@ private:
     }
 
     aVp.set(listener ? OBJECT_TO_JSVAL(listener) : JSVAL_NULL);
     return true;
   }
 
   static JSBool
   SetEventListener(JSContext* aCx, JSHandleObject aObj, JSHandleId aIdval, JSBool aStrict,
-                   JSMutableHandleValue aVp)
+                   JS::MutableHandle<JS::Value> aVp)
   {
     JS_ASSERT(JSID_IS_INT(aIdval));
     JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
 
     const char* name = sEventStrings[JSID_TO_INT(aIdval)];
     DedicatedWorkerGlobalScope* scope = GetInstancePrivate(aCx, aObj, name);
     if (!scope) {
       return false;
--- a/gfx/2d/SourceSurfaceD2DTarget.cpp
+++ b/gfx/2d/SourceSurfaceD2DTarget.cpp
@@ -94,16 +94,21 @@ SourceSurfaceD2DTarget::GetSRView()
 void
 SourceSurfaceD2DTarget::DrawTargetWillChange()
 {
   RefPtr<ID3D10Texture2D> oldTexture = mTexture;
 
   D3D10_TEXTURE2D_DESC desc;
   mTexture->GetDesc(&desc);
 
+  // Our original texture might implement the keyed mutex flag. We shouldn't
+  // need that here. We actually specifically don't want it since we don't lock
+  // our texture for usage!
+  desc.MiscFlags = 0;
+
   // Get a copy of the surface data so the content at snapshot time was saved.
   Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(mTexture));
   Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture);
 
   mBitmap = nullptr;
 
   DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat);
   mOwnsCopy = true;
--- a/gfx/layers/ipc/PGrallocBuffer.ipdl
+++ b/gfx/layers/ipc/PGrallocBuffer.ipdl
@@ -14,17 +14,16 @@ namespace layers {
 
 /**
  * This is a trivial protocol that's used to track gralloc buffers
  * across thread contexts.  A live PGrallocBuffer actor always
  * corresponds 1:1 to a pre-shared gralloc buffer (sharing is done by
  * the PGrallocBuffer constructor).
  */
 async protocol PGrallocBuffer {
-  // FIXME: Bug 783451: shouldn't be managed by PCompositor or PImageContainer
   manager PImageBridge or PLayerTransaction;
 
   /** Gralloc buffers can be "owned" by either parent or child. */
 both:
   async __delete__();
 };
 
 } // namespace layers
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -1,58 +1,133 @@
 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/pickle.h"
 
+#include "mozilla/Endian.h"
+#include "mozilla/TypeTraits.h"
+#include "mozilla/Util.h"
+
 #include <stdlib.h>
 
 #include <limits>
 #include <string>
 
 //------------------------------------------------------------------------------
 
+MOZ_STATIC_ASSERT(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
+		  "Insufficient alignment");
+
 // static
 const int Pickle::kPayloadUnit = 64;
 
 // We mark a read only pickle with a special capacity_.
 static const uint32_t kCapacityReadOnly = (uint32_t) -1;
 
 static const char kBytePaddingMarker = char(0xbf);
 
-// Payload is uint32_t aligned.
+namespace {
+
+// We want to copy data to our payload as efficiently as possible.
+// memcpy fits the bill for copying, but not all compilers or
+// architectures support inlining memcpy from void*, which has unknown
+// static alignment.  However, we know that all the members of our
+// payload will be aligned on memberAlignmentType boundaries.  We
+// therefore use that knowledge to construct a copier that will copy
+// efficiently (via standard C++ assignment mechanisms) if the datatype
+// needs that alignment or less, and memcpy otherwise.  (The compiler
+// may still inline memcpy, of course.)
+
+template<typename T, size_t size, bool hasSufficientAlignment>
+struct Copier
+{
+  static void Copy(T* dest, void** iter) {
+    memcpy(dest, *iter, sizeof(T));
+  }
+};
+
+// Copying 64-bit quantities happens often enough and can easily be made
+// worthwhile on 32-bit platforms, so handle it specially.  Only do it
+// if 64-bit types aren't sufficiently aligned; the alignment
+// requirements for them vary between 32-bit platforms.
+#ifndef HAVE_64BIT_OS
+template<typename T>
+struct Copier<T, sizeof(uint64_t), false>
+{
+  static void Copy(T* dest, void** iter) {
+#if MOZ_LITTLE_ENDIAN
+    static const int loIndex = 0, hiIndex = 1;
+#else
+    static const int loIndex = 1, hiIndex = 0;
+#endif
+    MOZ_STATIC_ASSERT(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
+		      "Pointers have different alignments");
+    uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
+    uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
+    uint32dest[loIndex] = src[loIndex];
+    uint32dest[hiIndex] = src[hiIndex];
+  }
+};
+#endif
+
+template<typename T, size_t size>
+struct Copier<T, size, true>
+{
+  static void Copy(T* dest, void** iter) {
+    // The reinterpret_cast is only safe if two conditions hold:
+    // (1) If the alignment of T* is the same as void*;
+    // (2) The alignment of the data in *iter is at least as
+    //     big as MOZ_ALIGNOF(T).
+    // Check the first condition, as the second condition is already
+    // known to be true, or we wouldn't be here.
+    MOZ_STATIC_ASSERT(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
+		      "Pointers have different alignments");
+    *dest = *(*reinterpret_cast<T**>(iter));
+  }
+};
+
+template<typename T>
+void CopyFromIter(T* dest, void** iter) {
+  MOZ_STATIC_ASSERT(mozilla::IsPod<T>::value, "Copied type must be a POD type");
+  Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter);
+}
+
+} // anonymous namespace
+
+// Payload is sizeof(Pickle::memberAlignmentType) aligned.
 
 Pickle::Pickle()
     : header_(NULL),
       header_size_(sizeof(Header)),
       capacity_(0),
       variable_buffer_offset_(0) {
   Resize(kPayloadUnit);
   header_->payload_size = 0;
 }
 
 Pickle::Pickle(int header_size)
     : header_(NULL),
-      header_size_(AlignInt(header_size, sizeof(uint32_t))),
+      header_size_(AlignInt(header_size)),
       capacity_(0),
       variable_buffer_offset_(0) {
-  DCHECK(static_cast<uint32_t>(header_size) >= sizeof(Header));
+  DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
   DCHECK(header_size <= kPayloadUnit);
   Resize(kPayloadUnit);
   header_->payload_size = 0;
 }
 
 Pickle::Pickle(const char* data, int data_len)
     : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
       header_size_(data_len - header_->payload_size),
       capacity_(kCapacityReadOnly),
       variable_buffer_offset_(0) {
   DCHECK(header_size_ >= sizeof(Header));
-  DCHECK(header_size_ == AlignInt(header_size_, sizeof(uint32_t)));
+  DCHECK(header_size_ == AlignInt(header_size_));
 }
 
 Pickle::Pickle(const Pickle& other)
     : header_(NULL),
       header_size_(other.header_size_),
       capacity_(0),
       variable_buffer_offset_(other.variable_buffer_offset_) {
   uint32_t payload_size = header_size_ + other.header_->payload_size;
@@ -93,67 +168,62 @@ bool Pickle::ReadBool(void** iter, bool*
 bool Pickle::ReadInt16(void** iter, int16_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt16(void** iter, uint16_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadInt(void** iter, int* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
-  // alignment.
-  // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
-  *result = *reinterpret_cast<int*>(*iter);
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadLong(void** iter, long* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   int64_t bigResult = 0;
   if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
     return false;
 
-  // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
-  // alignment.
-  memcpy(&bigResult, *iter, sizeof(bigResult));
+  CopyFromIter(&bigResult, iter);
   DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
   *result = static_cast<long>(bigResult);
 
   UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
@@ -162,19 +232,17 @@ bool Pickle::ReadULong(void** iter, unsi
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   uint64_t bigResult = 0;
   if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
     return false;
 
-  // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
-  // alignment.
-  memcpy(&bigResult, *iter, sizeof(bigResult));
+  CopyFromIter(&bigResult, iter);
   DCHECK(bigResult <= ULONG_MAX);
   *result = static_cast<unsigned long>(bigResult);
 
   UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadLength(void** iter, int* result) const {
@@ -189,124 +257,122 @@ bool Pickle::ReadSize(void** iter, size_
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   uint64_t bigResult = 0;
   if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
     return false;
 
-  // TODO(jar) bug 1129285: Pickle should be cleaned up, and not dependent on
-  // alignment.
-  memcpy(&bigResult, *iter, sizeof(bigResult));
+  CopyFromIter(&bigResult, iter);
   DCHECK(bigResult <= std::numeric_limits<size_t>::max());
   *result = static_cast<size_t>(bigResult);
 
   UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadInt32(void** iter, int32_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt32(void** iter, uint32_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadInt64(void** iter, int64_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt64(void** iter, uint64_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadDouble(void** iter, double* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadIntPtr(void** iter, intptr_t* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   int64_t bigResult = 0;
   if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
     return false;
 
-  memcpy(&bigResult, *iter, sizeof(bigResult));
+  CopyFromIter(&bigResult, iter);
   DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
   *result = static_cast<intptr_t>(bigResult);
 
   UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadUnsignedChar(void** iter, unsigned char* result) const {
   DCHECK(iter);
   if (!*iter)
     *iter = const_cast<char*>(payload());
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
     return false;
 
-  memcpy(result, *iter, sizeof(*result));
+  CopyFromIter(result, iter);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadString(void** iter, std::string* result) const {
   DCHECK(iter);
   if (!*iter)
@@ -406,19 +472,19 @@ bool Pickle::ReadData(void** iter, const
 
   return ReadBytes(iter, data, *length);
 }
 
 char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
   DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
 
   // write at an alignment-aligned offset from the beginning of the header
-  uint32_t offset = AlignInt(header_->payload_size, sizeof(uint32_t));
+  uint32_t offset = AlignInt(header_->payload_size);
   uint32_t padding = (header_size_ + offset) %  alignment;
-  uint32_t new_size = offset + padding + AlignInt(length, sizeof(uint32_t));
+  uint32_t new_size = offset + padding + AlignInt(length);
   uint32_t needed_size = header_size_ + new_size;
 
   if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
     return NULL;
 
   DCHECK(intptr_t(header_) % alignment == 0);
 
 #ifdef ARCH_CPU_64_BITS
@@ -436,18 +502,19 @@ char* Pickle::BeginWrite(uint32_t length
 
   header_->payload_size = new_size;
   return buffer;
 }
 
 void Pickle::EndWrite(char* dest, int length) {
   // Zero-pad to keep tools like purify from complaining about uninitialized
   // memory.
-  if (length % sizeof(uint32_t))
-    memset(dest + length, 0, sizeof(uint32_t) - (length % sizeof(uint32_t)));
+  if (length % sizeof(memberAlignmentType))
+    memset(dest + length, 0,
+	   sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType)));
 }
 
 bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) {
   DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
   char* dest = BeginWrite(data_len, alignment);
@@ -489,17 +556,17 @@ bool Pickle::WriteData(const char* data,
 
 char* Pickle::BeginWriteData(int length) {
   DCHECK_EQ(variable_buffer_offset_, 0U) <<
     "There can only be one variable buffer in a Pickle";
 
   if (!WriteInt(length))
     return NULL;
 
-  char *data_ptr = BeginWrite(length, sizeof(uint32_t));
+  char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType));
   if (!data_ptr)
     return NULL;
 
   variable_buffer_offset_ =
       data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
 
   // EndWrite doesn't necessarily have to be called after the write operation,
   // so we call it here to pad out what the caller will eventually write.
@@ -520,33 +587,33 @@ void Pickle::TrimWriteData(int new_lengt
   }
 
   // Update the payload size and variable buffer size
   header_->payload_size -= (*cur_length - new_length);
   *cur_length = new_length;
 }
 
 bool Pickle::Resize(uint32_t new_capacity) {
-  new_capacity = AlignInt(new_capacity, kPayloadUnit);
+  new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity);
 
   void* p = realloc(header_, new_capacity);
   if (!p)
     return false;
 
   header_ = reinterpret_cast<Header*>(p);
   capacity_ = new_capacity;
   return true;
 }
 
 // static
 const char* Pickle::FindNext(uint32_t header_size,
                              const char* start,
                              const char* end) {
-  DCHECK(header_size == AlignInt(header_size, sizeof(uint32_t)));
-  DCHECK(header_size <= static_cast<uint32_t>(kPayloadUnit));
+  DCHECK(header_size == AlignInt(header_size));
+  DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
 
   const Header* hdr = reinterpret_cast<const Header*>(start);
   const char* payload_base = start + header_size;
   const char* payload_end = payload_base + hdr->payload_size;
   if (payload_end < payload_base)
     return NULL;
 
   return (payload_end > end) ? NULL : payload_end;
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -79,17 +79,17 @@ class Pickle {
   bool ReadDouble(void** iter, double* result) const;
   bool ReadIntPtr(void** iter, intptr_t* result) const;
   bool ReadUnsignedChar(void** iter, unsigned char* result) const;
   bool ReadString(void** iter, std::string* result) const;
   bool ReadWString(void** iter, std::wstring* result) const;
   bool ReadString16(void** iter, string16* result) const;
   bool ReadData(void** iter, const char** data, int* length) const;
   bool ReadBytes(void** iter, const char** data, int length,
-                 uint32_t alignment = sizeof(uint32_t)) const;
+                 uint32_t alignment = sizeof(memberAlignmentType)) const;
 
   // Safer version of ReadInt() checks for the result not being negative.
   // Use it for reading the object sizes.
   bool ReadLength(void** iter, int* result) const;
 
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
@@ -144,17 +144,17 @@ class Pickle {
   bool WriteUnsignedChar(unsigned char value) {
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
   bool WriteString16(const string16& value);
   bool WriteData(const char* data, int length);
   bool WriteBytes(const void* data, int data_len,
-                  uint32_t alignment = sizeof(uint32_t));
+                  uint32_t alignment = sizeof(memberAlignmentType));
 
   // Same as WriteData, but allows the caller to write directly into the
   // Pickle. This saves a copy in cases where the data is not already
   // available in a buffer. The caller should take care to not write more
   // than the length it declares it will. Use ReadData to get the data.
   // Returns NULL on failure.
   //
   // The returned pointer will only be valid until the next write operation
@@ -201,16 +201,18 @@ class Pickle {
   bool IteratorHasRoomFor(const void* iter, int len) const {
     if ((len < 0) || (iter < header_) || iter > end_of_payload())
       return false;
     const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
     // Watch out for overflow in pointer calculation, which wraps.
     return (iter <= end_of_region) && (end_of_region <= end_of_payload());
   }
 
+  typedef uint32_t memberAlignmentType;
+
  protected:
   uint32_t payload_size() const { return header_->payload_size; }
 
   char* payload() {
     return reinterpret_cast<char*>(header_) + header_size_;
   }
   const char* payload() const {
     return reinterpret_cast<const char*>(header_) + header_size_;
@@ -241,26 +243,35 @@ class Pickle {
   void EndWrite(char* dest, int length);
 
   // Resize the capacity, note that the input value should include the size of
   // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
   // A realloc() failure will cause a Resize failure... and caller should check
   // the return result for true (i.e., successful resizing).
   bool Resize(uint32_t new_capacity);
 
-  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
-  static uint32_t AlignInt(uint32_t i, int alignment) {
-    return i + (alignment - (i % alignment)) % alignment;
+  // Round 'bytes' up to the next multiple of 'alignment'.  'alignment' must be
+  // a power of 2.
+  template<uint32_t alignment> struct ConstantAligner {
+    static uint32_t align(int bytes) {
+      MOZ_STATIC_ASSERT((alignment & (alignment - 1)) == 0,
+			"alignment must be a power of two");
+      return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
+    }
+  };
+
+  static uint32_t AlignInt(int bytes) {
+    return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
   }
 
   // Moves the iterator by the given number of bytes, making sure it is aligned.
   // Pointer (iterator) is NOT aligned, but the change in the pointer
-  // is guaranteed to be a multiple of sizeof(uint32_t).
+  // is guaranteed to be a multiple of sizeof(memberAlignmentType).
   static void UpdateIter(void** iter, int bytes) {
-    *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32_t));
+    *iter = static_cast<char*>(*iter) + AlignInt(bytes);
   }
 
   // Find the end of the pickled data that starts at range_start.  Returns NULL
   // if the entire Pickle is not found in the given data range.
   static const char* FindNext(uint32_t header_size,
                               const char* range_start,
                               const char* range_end);
 
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParam.ipdlh
@@ -0,0 +1,15 @@
+include protocol PTestIndirectProtocolParamSecond;
+
+namespace mozilla {
+namespace _ipdltest {
+
+struct IndirectParamStruct {
+    PTestIndirectProtocolParamSecond actor;
+};
+
+union IndirectParamUnion {
+    IndirectParamStruct;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamFirst.ipdl
@@ -0,0 +1,19 @@
+include protocol PTestIndirectProtocolParamManage;
+// FIXME/bug 792908 protocol PTestIndirectProtocolParamSecond is
+// already included in PTestIndirectProtocolParam.ipdlh
+include protocol PTestIndirectProtocolParamSecond;
+include PTestIndirectProtocolParam;
+
+namespace mozilla {
+namespace _ipdltest {
+
+sync protocol PTestIndirectProtocolParamFirst {
+    manager PTestIndirectProtocolParamManage;
+parent:
+    sync Test(IndirectParamUnion actor);
+both:
+    __delete__();
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamManage.ipdl
@@ -0,0 +1,17 @@
+include protocol PTestIndirectProtocolParamFirst;
+include protocol PTestIndirectProtocolParamSecond;
+
+namespace mozilla {
+namespace _ipdltest {
+
+sync protocol PTestIndirectProtocolParamManage {
+    manages PTestIndirectProtocolParamFirst;
+    manages PTestIndirectProtocolParamSecond;
+both:
+    PTestIndirectProtocolParamFirst();
+    PTestIndirectProtocolParamSecond();
+    __delete__();
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestIndirectProtocolParamSecond.ipdl
@@ -0,0 +1,13 @@
+include protocol PTestIndirectProtocolParamManage;
+
+namespace mozilla {
+namespace _ipdltest {
+
+sync protocol PTestIndirectProtocolParamSecond {
+    manager PTestIndirectProtocolParamManage;
+both:
+    __delete__();
+};
+
+}
+}
--- a/ipc/ipdl/test/cxx/ipdl.mk
+++ b/ipc/ipdl/test/cxx/ipdl.mk
@@ -45,9 +45,13 @@ IPDLSRCS =					\
   PTestShutdownSubsub.ipdl			\
   PTestStackHooks.ipdl				\
   PTestSyncError.ipdl                           \
   PTestSyncHang.ipdl                            \
   PTestSyncWakeup.ipdl				\
   PTestSysVShmem.ipdl				\
   PTestBadActor.ipdl                            \
   PTestBadActorSub.ipdl                         \
+  PTestIndirectProtocolParam.ipdlh	        \
+  PTestIndirectProtocolParamManage.ipdl         \
+  PTestIndirectProtocolParamFirst.ipdl	        \
+  PTestIndirectProtocolParamSecond.ipdl	        \
   $(NULL)
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -383,17 +383,17 @@ jsval_to_nsString(JSContext* cx, jsid fr
         *to = chars;
         return true;
     }
     return false;
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                      JSMutableHandleValue vp)
+                                      MutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_AddProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
     ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty");
 
@@ -410,17 +410,17 @@ ObjectWrapperParent::CPOW_AddProperty(JS
     return (self->Manager()->RequestRunToCompletion() &&
             self->CallAddProperty(in_id,
                                   aco.StatusPtr()) &&
             aco.Ok());
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
-                                      JSMutableHandleValue vp)
+                                      MutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_GetProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
     ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty");
 
@@ -437,17 +437,17 @@ ObjectWrapperParent::CPOW_GetProperty(JS
             self->CallGetProperty(in_id,
                                   aco.StatusPtr(), &out_v) &&
             aco.Ok() &&
             self->jsval_from_JSVariant(cx, out_v, vp.address()));
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, 
-                                      JSBool strict, JSMutableHandleValue vp)
+                                      JSBool strict, MutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_SetProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
     ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty");
 
@@ -609,17 +609,17 @@ ObjectWrapperParent::CPOW_NewResolve(JSC
         JS_DefinePropertyById(cx, obj2, id, JSVAL_VOID, NULL, NULL,
                               JSPROP_ENUMERATE);
     }
     return JS_TRUE;
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type,
-                                  JSMutableHandleValue vp)
+                                  MutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_Convert (to %s)...",
               JS_GetTypeName(cx, type)));
 
     ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert");
 
@@ -703,17 +703,17 @@ ObjectWrapperParent::CPOW_Construct(JSCo
 
     return (constructor->Manager()->RequestRunToCompletion() &&
             constructor->CallConstruct(in_argv, aco.StatusPtr(), &out_powp) &&
             aco.Ok() &&
             jsval_from_PObjectWrapperParent(cx, out_powp, vp));
 }
 
 /*static*/ JSBool
-ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue v,
+ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, MutableHandleValue v,
                                       JSBool *bp)
 {
     CPOW_LOG(("Calling CPOW_HasInstance..."));
 
     *bp = JS_FALSE;
 
     ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
--- a/js/ipc/ObjectWrapperParent.h
+++ b/js/ipc/ObjectWrapperParent.h
@@ -54,52 +54,52 @@ protected:
 
     ContextWrapperParent* Manager();
 
 private:
 
     mutable JSObject* mObj;
 
     static JSBool
-    CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+    CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandleValue vp);
 
     static JSBool
     CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded);
 
     static JSBool
-    CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+    CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandleValue vp);
     
     static JSBool
-    CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp);
+    CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandleValue vp);
 
     JSBool NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp);
     JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp);
     JSBool NewEnumerateDestroy(JSContext* cx, jsval state);
     static JSBool
     CPOW_NewEnumerate(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
                       jsval *statep, jsid *idp);
 
     static JSBool
     CPOW_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
                     JS::MutableHandleObject objp);
 
     static JSBool
-    CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp);
+    CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandleValue vp);
 
     static void
     CPOW_Finalize(js::FreeOp* fop, JSObject* obj);
 
     static JSBool
     CPOW_Call(JSContext* cx, unsigned argc, jsval* vp);
 
     static JSBool
     CPOW_Construct(JSContext *cx, unsigned argc, jsval *vp);
 
     static JSBool
-    CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue vp, JSBool *bp);
+    CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JS::MutableHandleValue vp, JSBool *bp);
 
     static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
     static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
                                      jsval* to);
     static bool boolean_from_JSVariant(JSContext* cx, const JSVariant& from,
                                        JSBool* to);
     static bool
     JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to);
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -97,17 +97,17 @@
  */
 
 namespace js {
 
 class Module;
 class ScriptSourceObject;
 
 template <typename T>
-struct RootMethods {};
+struct GCMethods {};
 
 template <typename T>
 class RootedBase {};
 
 template <typename T>
 class HandleBase {};
 
 template <typename T>
@@ -176,23 +176,23 @@ struct JS_PUBLIC_API(NullPtr)
  */
 template <typename T>
 class Heap : public js::HeapBase<T>
 {
   public:
     Heap() {
         MOZ_STATIC_ASSERT(sizeof(T) == sizeof(Heap<T>),
                           "Heap<T> must be binary compatible with T.");
-        init(js::RootMethods<T>::initial());
+        init(js::GCMethods<T>::initial());
     }
     explicit Heap(T p) { init(p); }
     explicit Heap(const Heap<T> &p) { init(p.ptr); }
 
     ~Heap() {
-        if (js::RootMethods<T>::needsPostBarrier(ptr))
+        if (js::GCMethods<T>::needsPostBarrier(ptr))
             relocate();
     }
 
     bool operator!=(const T &other) const { return ptr != other; }
     bool operator==(const T &other) const { return ptr == other; }
 
     operator T() const { return ptr; }
     T operator->() const { return ptr; }
@@ -202,46 +202,46 @@ class Heap : public js::HeapBase<T>
     T *unsafeGet() { return &ptr; }
 
     Heap<T> &operator=(T p) {
         set(p);
         return *this;
     }
 
     void set(T newPtr) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr));
-        if (js::RootMethods<T>::needsPostBarrier(newPtr)) {
+        JS_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
+        if (js::GCMethods<T>::needsPostBarrier(newPtr)) {
             ptr = newPtr;
             post();
-        } else if (js::RootMethods<T>::needsPostBarrier(ptr)) {
+        } else if (js::GCMethods<T>::needsPostBarrier(ptr)) {
             relocate();  /* Called before overwriting ptr. */
             ptr = newPtr;
         } else {
             ptr = newPtr;
         }
     }
 
   private:
     void init(T newPtr) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
         ptr = newPtr;
-        if (js::RootMethods<T>::needsPostBarrier(ptr))
+        if (js::GCMethods<T>::needsPostBarrier(ptr))
             post();
     }
 
     void post() {
 #ifdef JSGC_GENERATIONAL
-        JS_ASSERT(js::RootMethods<T>::needsPostBarrier(ptr));
-        js::RootMethods<T>::postBarrier(&ptr);
+        JS_ASSERT(js::GCMethods<T>::needsPostBarrier(ptr));
+        js::GCMethods<T>::postBarrier(&ptr);
 #endif
     }
 
     void relocate() {
 #ifdef JSGC_GENERATIONAL
-        js::RootMethods<T>::relocate(&ptr);
+        js::GCMethods<T>::relocate(&ptr);
 #endif
     }
 
     T ptr;
 };
 
 /*
  * Reference to a T that has been rooted elsewhere. This is most useful
@@ -358,17 +358,17 @@ typedef Handle<Value>                   
  */
 template <typename T>
 class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
 {
   public:
     inline MutableHandle(Rooted<T> *root);
 
     void set(T v) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(v));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(v));
         *ptr = v;
     }
 
     /*
      * This may be called only if the location of the T is guaranteed
      * to be marked (for some reason other than being a Rooted),
      * e.g., if it is guaranteed to be reachable from an implicit root.
      *
@@ -476,17 +476,17 @@ class InternalHandle<T*>
  */
 template <typename T>
 struct RootKind<T *>
 {
     static ThingRootKind rootKind() { return T::rootKind(); }
 };
 
 template <typename T>
-struct RootMethods<T *>
+struct GCMethods<T *>
 {
     static T *initial() { return NULL; }
     static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
     static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
     static bool needsPostBarrier(T *v) { return v; }
 #ifdef JSGC_GENERATIONAL
     static void postBarrier(T **vp) {
         JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
@@ -523,49 +523,49 @@ class MOZ_STACK_CLASS Rooted : public js
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         commonInit(pt->thingGCRooters);
 #endif
     }
 
   public:
     Rooted(JSContext *cx
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : ptr(js::RootMethods<T>::initial())
+      : ptr(js::GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(cx);
     }
 
     Rooted(JSContext *cx, T initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(cx);
     }
 
     Rooted(js::PerThreadData *pt
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : ptr(js::RootMethods<T>::initial())
+      : ptr(js::GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(js::PerThreadDataFriendFields::get(pt));
     }
 
     Rooted(js::PerThreadData *pt, T initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(js::PerThreadDataFriendFields::get(pt));
     }
 
     Rooted(JSRuntime *rt
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : ptr(js::RootMethods<T>::initial())
+      : ptr(js::GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(js::PerThreadDataFriendFields::getMainThread(rt));
     }
 
     Rooted(JSRuntime *rt, T initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
@@ -592,43 +592,43 @@ class MOZ_STACK_CLASS Rooted : public js
     operator const T&() const { return ptr; }
     T operator->() const { return ptr; }
     T *address() { return &ptr; }
     const T *address() const { return &ptr; }
     T &get() { return ptr; }
     const T &get() const { return ptr; }
 
     T &operator=(T value) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(value));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(value));
         ptr = value;
         return ptr;
     }
 
     T &operator=(const Rooted &value) {
         ptr = value;
         return ptr;
     }
 
     void set(T value) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(value));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(value));
         ptr = value;
     }
 
     bool operator!=(const T &other) const { return ptr != other; }
     bool operator==(const T &other) const { return ptr == other; }
 
   private:
     void commonInit(Rooted<void*> **thingGCRooters) {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
-        js::ThingRootKind kind = js::RootMethods<T>::kind();
+        js::ThingRootKind kind = js::GCMethods<T>::kind();
         this->stack = &thingGCRooters[kind];
         this->prev = *stack;
         *stack = reinterpret_cast<Rooted<void*>*>(this);
 
-        JS_ASSERT(!js::RootMethods<T>::poisoned(ptr));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(ptr));
 #endif
     }
 
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     Rooted<void*> **stack, *prev;
 #endif
 
 #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
@@ -743,17 +743,17 @@ class SkipRoot
 
 /* Interface substitute for Rooted<T> which does not root the variable's memory. */
 template <typename T>
 class FakeRooted : public RootedBase<T>
 {
   public:
     FakeRooted(JSContext *cx
                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-      : ptr(RootMethods<T>::initial())
+      : ptr(GCMethods<T>::initial())
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     FakeRooted(JSContext *cx, T initial
                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
     {
@@ -763,17 +763,17 @@ class FakeRooted : public RootedBase<T>
     operator T() const { return ptr; }
     T operator->() const { return ptr; }
     T *address() { return &ptr; }
     const T *address() const { return &ptr; }
     T &get() { return ptr; }
     const T &get() const { return ptr; }
 
     T &operator=(T value) {
-        JS_ASSERT(!RootMethods<T>::poisoned(value));
+        JS_ASSERT(!GCMethods<T>::poisoned(value));
         ptr = value;
         return ptr;
     }
 
     bool operator!=(const T &other) const { return ptr != other; }
     bool operator==(const T &other) const { return ptr == other; }
 
   private:
@@ -793,17 +793,17 @@ class FakeMutableHandle : public js::Mut
         ptr = t;
     }
 
     FakeMutableHandle(FakeRooted<T> *root) {
         ptr = root->address();
     }
 
     void set(T v) {
-        JS_ASSERT(!js::RootMethods<T>::poisoned(v));
+        JS_ASSERT(!js::GCMethods<T>::poisoned(v));
         *ptr = v;
     }
 
     T *address() const { return ptr; }
     T get() const { return *ptr; }
 
     operator T() const { return get(); }
     T operator->() const { return get(); }
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -1396,24 +1396,24 @@ SameType(const Value &lhs, const Value &
 namespace JS {
 JS_PUBLIC_API(void) HeapValuePostBarrier(Value *valuep);
 JS_PUBLIC_API(void) HeapValueRelocate(Value *valuep);
 }
 #endif
 
 namespace js {
 
-template <> struct RootMethods<const JS::Value>
+template <> struct GCMethods<const JS::Value>
 {
     static JS::Value initial() { return JS::UndefinedValue(); }
     static ThingRootKind kind() { return THING_ROOT_VALUE; }
     static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
 };
 
-template <> struct RootMethods<JS::Value>
+template <> struct GCMethods<JS::Value>
 {
     static JS::Value initial() { return JS::UndefinedValue(); }
     static ThingRootKind kind() { return THING_ROOT_VALUE; }
     static bool poisoned(const JS::Value &v) { return JS::IsPoisonedValue(v); }
     static bool needsPostBarrier(const JS::Value &v) { return v.isMarkable(); }
 #ifdef JSGC_GENERATIONAL
     static void postBarrier(JS::Value *v) { JS::HeapValuePostBarrier(v); }
     static void relocate(JS::Value *v) { JS::HeapValueRelocate(v); }
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1123,27 +1123,17 @@ MapObject::mark(JSTracer *trc, JSObject 
 #ifdef JSGC_GENERATIONAL
 template <typename TableType>
 class OrderedHashTableRef : public gc::BufferableRef
 {
     TableType *table;
     HashableValue key;
 
   public:
-    OrderedHashTableRef(TableType *t, const HashableValue &k) : table(t), key(k) {}
-
-    bool match(void *location) {
-        if (!table->has(key))
-            return false;
-        for (typename TableType::Range r = table->all(); !r.empty(); r.popFront()) {
-            if ((void*)&r.front() == location)
-                return true;
-        }
-        return false;
-    }
+    explicit OrderedHashTableRef(TableType *t, const HashableValue &k) : table(t), key(k) {}
 
     void mark(JSTracer *trc) {
         HashableValue prior = key;
         key = key.mark(trc);
         table->rekeyOneEntry(prior, key);
     }
 };
 #endif
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -12,16 +12,17 @@ endif
 
 # Integrate with mozbuild-generated make files. We first verify that no
 # variables provided by the automatically generated .mk files are
 # present. If they are, this is a violation of the separation of
 # responsibility between Makefile.in and mozbuild files.
 _MOZBUILD_EXTERNAL_VARIABLES := \
   DIRS \
   HOST_CSRCS \
+  HOST_LIBRARY_NAME \
   MODULE \
   PARALLEL_DIRS \
   TEST_DIRS \
   TIERS \
   TOOL_DIRS \
   XPIDL_MODULE \
   $(NULL)
 
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -169,17 +169,17 @@ namespace CType {
   static JSBool NameGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval,
     MutableHandleValue vp);
   static JSBool SizeGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval,
     MutableHandleValue vp);
   static JSBool PtrGetter(JSContext* cx, JSHandleObject obj, JSHandleId idval, MutableHandleValue vp);
   static JSBool CreateArray(JSContext* cx, unsigned argc, jsval* vp);
   static JSBool ToString(JSContext* cx, unsigned argc, jsval* vp);
   static JSBool ToSource(JSContext* cx, unsigned argc, jsval* vp);
-  static JSBool HasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue v, JSBool* bp);
+  static JSBool HasInstance(JSContext* cx, JSHandleObject obj, MutableHandleValue v, JSBool* bp);
 
 
   /*
    * Get the global "ctypes" object.
    *
    * |obj| must be a CType object.
    *
    * This function never returns NULL.
@@ -3742,17 +3742,17 @@ CType::ToSource(JSContext* cx, unsigned 
   if (!result)
     return JS_FALSE;
 
   args.rval().setString(result);
   return JS_TRUE;
 }
 
 JSBool
-CType::HasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue v, JSBool* bp)
+CType::HasInstance(JSContext* cx, JSHandleObject obj, MutableHandleValue v, JSBool* bp)
 {
   JS_ASSERT(CType::IsCType(obj));
 
   jsval slot = JS_GetReservedSlot(obj, SLOT_PROTO);
   JS::Rooted<JSObject*> prototype(cx, &slot.toObject());
   JS_ASSERT(prototype);
   JS_ASSERT(CData::IsCDataProto(prototype));
 
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6498,20 +6498,19 @@ template <>
 ParseNode *
 Parser<FullParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags)
 {
     ParseNode *pn = NullaryNode::create(PNK_REGEXP, &handler);
     if (!pn)
         return NULL;
 
     const StableCharPtr chars(buf, length);
-    RegExpStatics *res = context->regExpStatics();
 
     Rooted<RegExpObject*> reobj(context);
-    if (context->hasfp())
+    if (RegExpStatics *res = context->regExpStatics())
         reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
     else
         reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
 
     if (!reobj)
         return NULL;
 
     pn->pn_objbox = newObjectBox(reobj);
@@ -6523,20 +6522,19 @@ Parser<FullParseHandler>::newRegExp(cons
 }
 
 template <>
 SyntaxParseHandler::Node
 Parser<SyntaxParseHandler>::newRegExp(const jschar *buf, size_t length, RegExpFlag flags)
 {
     // Create the regexp even when doing a syntax parse, to check the regexp's syntax.
     const StableCharPtr chars(buf, length);
-    RegExpStatics *res = context->regExpStatics();
 
     RegExpObject *reobj;
-    if (context->hasfp())
+    if (RegExpStatics *res = context->regExpStatics())
         reobj = RegExpObject::create(context, res, chars.get(), length, flags, &tokenStream);
     else
         reobj = RegExpObject::createNoStatics(context, chars.get(), length, flags, &tokenStream);
 
     return reobj ? SyntaxParseHandler::NodeGeneric : SyntaxParseHandler::NodeFailure;
 }
 
 template <typename ParseHandler>
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -407,22 +407,16 @@ class DenseRangeRef : public gc::Buffera
 
   public:
     DenseRangeRef(JSObject *obj, uint32_t start, uint32_t end)
       : owner(obj), start(start), end(end)
     {
         JS_ASSERT(start < end);
     }
 
-    bool match(void *location) {
-        uint32_t len = owner->getDenseInitializedLength();
-        return location >= &owner->getDenseElement(Min(start, len)) &&
-               location <= &owner->getDenseElement(Min(end, len)) - 1;
-    }
-
     void mark(JSTracer *trc) {
         /* Apply forwarding, if we have already visited owner. */
         IsObjectMarked(&owner);
         uint32_t initLen = owner->getDenseInitializedLength();
         uint32_t clampedStart = Min(start, initLen);
         gc::MarkArraySlots(trc, Min(end, initLen) - clampedStart,
                            owner->getDenseElements() + clampedStart, "element");
     }
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -100,14 +100,48 @@ EndVerifyPreBarriers(JSRuntime *rt);
 void
 StartVerifyPostBarriers(JSRuntime *rt);
 
 void
 EndVerifyPostBarriers(JSRuntime *rt);
 
 void
 FinishVerifier(JSRuntime *rt);
+
+class AutoStopVerifyingBarriers
+{
+    JSRuntime *runtime;
+    bool restartPreVerifier;
+    bool restartPostVerifier;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    AutoStopVerifyingBarriers(JSRuntime *rt, bool isShutdown
+                       MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : runtime(rt)
+    {
+        restartPreVerifier = !isShutdown && rt->gcVerifyPreData;
+        restartPostVerifier = !isShutdown && rt->gcVerifyPostData;
+        if (rt->gcVerifyPreData)
+            EndVerifyPreBarriers(rt);
+        if (rt->gcVerifyPostData)
+            EndVerifyPostBarriers(rt);
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    }
+
+    ~AutoStopVerifyingBarriers() {
+        if (restartPreVerifier)
+            StartVerifyPreBarriers(runtime);
+        if (restartPostVerifier)
+            StartVerifyPostBarriers(runtime);
+    }
+};
+#else
+struct AutoStopVerifyingBarriers
+{
+    AutoStopVerifyingBarriers(JSRuntime *, bool) {}
+};
 #endif /* JS_GC_ZEAL */
 
 } /* namespace gc */
 } /* namespace js */
 
 #endif /* jsgc_internal_h___ */
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -8,16 +8,17 @@
 
 #include "mozilla/DebugOnly.h"
 
 #include "ion/IonCode.h"
 #include "vm/Shape.h"
 
 #include "jscompartmentinlines.h"
 
+#include "gc/Nursery-inl.h"
 #include "vm/Shape-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::DebugOnly;
 
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -31,16 +31,29 @@ js::Nursery::init()
     JS_ASSERT(start() == 0);
 
     if (!hugeSlots.init())
         return false;
 
     fallbackBitmap.clear(false);
 
     void *heap = MapAlignedPages(NurserySize, Alignment);
+#ifdef JSGC_ROOT_ANALYSIS
+    // Our poison pointers are not guaranteed to be invalid on 64-bit
+    // architectures, and often are valid. We can't just reserve the full
+    // poison range, because it might already have been taken up by something
+    // else (shared library, previous allocation). So we'll just loop and
+    // discard poison pointers until we get something valid.
+    //
+    // This leaks all of these poisoned pointers. It would be better if they
+    // were marked as uncommitted, but it's a little complicated to avoid
+    // clobbering pre-existing unrelated mappings.
+    while (IsPoisonedPtr(heap) || IsPoisonedPtr((void*)(uintptr_t(heap) + NurserySize)))
+        heap = MapAlignedPages(NurserySize, Alignment);
+#endif
     if (!heap)
         return false;
 
     JSRuntime *rt = runtime();
     rt->gcNurseryStart_ = uintptr_t(heap);
     rt->gcNurseryEnd_ = chunk(LastNurseryChunk).end();
     numActiveChunks_ = 1;
     setCurrentChunk(0);
@@ -506,16 +519,18 @@ js::Nursery::collect(JSRuntime *rt, JS::
     if (!isEnabled())
         return;
 
     if (position() == start())
         return;
 
     rt->gcHelperThread.waitBackgroundSweepEnd();
 
+    AutoStopVerifyingBarriers av(rt, false);
+
     /* Move objects pointed to by roots from the nursery to the major heap. */
     MinorCollectionTracer trc(rt, this);
     MarkRuntime(&trc);
     Debugger::markAll(&trc);
     for (CompartmentsIter comp(rt); !comp.done(); comp.next()) {
         comp->markAllCrossCompartmentWrappers(&trc);
         comp->markAllInitialShapeTableEntries(&trc);
     }
--- a/js/src/gc/StoreBuffer.cpp
+++ b/js/src/gc/StoreBuffer.cpp
@@ -39,21 +39,20 @@ StoreBuffer::SlotEdge::deref() const
 }
 
 JS_ALWAYS_INLINE void *
 StoreBuffer::SlotEdge::location() const
 {
     return (void *)slotLocation();
 }
 
-template <typename NurseryType>
 JS_ALWAYS_INLINE bool
-StoreBuffer::SlotEdge::inRememberedSet(NurseryType *nursery) const
+StoreBuffer::SlotEdge::inRememberedSet(const Nursery &nursery) const
 {
-    return !nursery->isInside(object) && nursery->isInside(deref());
+    return !nursery.isInside(object) && nursery.isInside(deref());
 }
 
 JS_ALWAYS_INLINE bool
 StoreBuffer::SlotEdge::isNullEdge() const
 {
     return !deref();
 }
 
@@ -97,19 +96,18 @@ StoreBuffer::MonoTypeBuffer<T>::disable(
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::clear()
 {
     pos = base;
 }
 
 template <typename T>
-template <typename NurseryType>
 void
-StoreBuffer::MonoTypeBuffer<T>::compactNotInSet(NurseryType *nursery)
+StoreBuffer::MonoTypeBuffer<T>::compactNotInSet(const Nursery &nursery)
 {
     T *insert = base;
     for (T *v = base; v != pos; ++v) {
         if (v->inRememberedSet(nursery))
             *insert++ = *v;
     }
     pos = insert;
 }
@@ -131,22 +129,17 @@ StoreBuffer::MonoTypeBuffer<T>::compactR
     pos = insert;
     duplicates.clear();
 }
 
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::compact()
 {
-#ifdef JS_GC_ZEAL
-    if (owner->runtime->gcVerifyPostData)
-        compactNotInSet(&owner->runtime->gcVerifierNursery);
-    else
-#endif
-        compactNotInSet(&owner->runtime->gcNursery);
+    compactNotInSet(owner->runtime->gcNursery);
     compactRemoveDuplicates();
 }
 
 template <typename T>
 void
 StoreBuffer::MonoTypeBuffer<T>::mark(JSTracer *trc)
 {
     compact();
@@ -156,64 +149,32 @@ StoreBuffer::MonoTypeBuffer<T>::mark(JST
 
         if (edge.isNullEdge())
             continue;
 
         edge.mark(trc);
     }
 }
 
-template <typename T>
-bool
-StoreBuffer::MonoTypeBuffer<T>::accumulateEdges(EdgeSet &edges)
-{
-    compact();
-    T *cursor = base;
-    while (cursor != pos) {
-        T edge = *cursor++;
-
-        /* Note: the relocatable buffer is allowed to store pointers to NULL. */
-        if (edge.isNullEdge())
-            continue;
-        if (!edges.putNew(edge.location()))
-            return false;
-    }
-    return true;
-}
-
 namespace js {
 namespace gc {
 class AccumulateEdgesTracer : public JSTracer
 {
     EdgeSet *edges;
 
     static void tracer(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) {
         AccumulateEdgesTracer *trc = static_cast<AccumulateEdgesTracer *>(jstrc);
         trc->edges->put(thingp);
     }
 
   public:
     AccumulateEdgesTracer(JSRuntime *rt, EdgeSet *edgesArg) : edges(edgesArg) {
         JS_TracerInit(this, rt, AccumulateEdgesTracer::tracer);
     }
 };
-
-template <>
-bool
-StoreBuffer::MonoTypeBuffer<StoreBuffer::WholeCellEdges>::accumulateEdges(EdgeSet &edges)
-{
-    compact();
-    AccumulateEdgesTracer trc(owner->runtime, &edges);
-    StoreBuffer::WholeCellEdges *cursor = base;
-    while (cursor != pos) {
-        cursor->mark(&trc);
-        cursor++;
-    }
-    return true;
-}
 } /* namespace gc */
 } /* namespace js */
 
 /*** RelocatableMonoTypeBuffer ***/
 
 template <typename T>
 void
 StoreBuffer::RelocatableMonoTypeBuffer<T>::compactMoved()
@@ -281,32 +242,16 @@ StoreBuffer::GenericBuffer::mark(JSTrace
 
         BufferableRef *edge = reinterpret_cast<BufferableRef *>(p);
         edge->mark(trc);
 
         p += size;
     }
 }
 
-bool
-StoreBuffer::GenericBuffer::containsEdge(void *location) const
-{
-    uint8_t *p = base;
-    while (p < pos) {
-        unsigned size = *((unsigned *)p);
-        p += sizeof(unsigned);
-
-        if (((BufferableRef *)p)->match(location))
-            return true;
-
-        p += size;
-    }
-    return false;
-}
-
 /*** Edges ***/
 
 void
 StoreBuffer::CellPtrEdge::mark(JSTracer *trc)
 {
     MarkObjectRoot(trc, reinterpret_cast<JSObject**>(edge), "store buffer edge");
 }
 
@@ -440,51 +385,16 @@ StoreBuffer::setAboutToOverflow()
 void
 StoreBuffer::setOverflowed()
 {
     JS_ASSERT(enabled);
     overflowed = true;
 }
 
 bool
-StoreBuffer::coalesceForVerification()
-{
-    if (!edgeSet.initialized()) {
-        if (!edgeSet.init())
-            return false;
-    }
-    JS_ASSERT(edgeSet.empty());
-    if (!bufferVal.accumulateEdges(edgeSet))
-        return false;
-    if (!bufferCell.accumulateEdges(edgeSet))
-        return false;
-    if (!bufferSlot.accumulateEdges(edgeSet))
-        return false;
-    if (!bufferWholeCell.accumulateEdges(edgeSet))
-        return false;
-    if (!bufferRelocVal.accumulateEdges(edgeSet))
-        return false;
-    if (!bufferRelocCell.accumulateEdges(edgeSet))
-        return false;
-    return true;
-}
-
-bool
-StoreBuffer::containsEdgeAt(void *loc) const
-{
-    return edgeSet.has(loc) || bufferGeneric.containsEdge(loc);
-}
-
-void
-StoreBuffer::releaseVerificationData()
-{
-    edgeSet.finish();
-}
-
-bool
 StoreBuffer::inParallelSection() const
 {
     return InParallelSection();
 }
 
 JS_PUBLIC_API(void)
 JS::HeapCellPostBarrier(js::gc::Cell **cellp)
 {
--- a/js/src/gc/StoreBuffer.h
+++ b/js/src/gc/StoreBuffer.h
@@ -17,69 +17,25 @@
 #include "jsalloc.h"
 #include "jsobj.h"
 
 namespace js {
 namespace gc {
 
 class AccumulateEdgesTracer;
 
-#ifdef JS_GC_ZEAL
-/*
- * Note: this is a stub Nursery that does not actually contain a heap, just a
- * set of pointers which are "inside" the nursery to implement verification.
- */
-class VerifierNursery
-{
-    HashSet<const void *, PointerHasher<const void *, 3>, SystemAllocPolicy> nursery;
-
-  public:
-    explicit VerifierNursery() : nursery() {}
-
-    bool enable() {
-        if (!nursery.initialized())
-            return nursery.init();
-        return true;
-    }
-
-    void disable() {
-        if (!nursery.initialized())
-            return;
-        nursery.finish();
-    }
-
-    bool isEnabled() const {
-        return nursery.initialized();
-    }
-
-    bool clear() {
-        disable();
-        return enable();
-    }
-
-    bool isInside(const void *cell) const {
-        return nursery.initialized() && nursery.has(cell);
-    }
-
-    void insertPointer(void *cell) {
-        nursery.putNew(cell);
-    }
-};
-#endif /* JS_GC_ZEAL */
-
 /*
  * BufferableRef represents an abstract reference for use in the generational
  * GC's remembered set. Entries in the store buffer that cannot be represented
  * with the simple pointer-to-a-pointer scheme must derive from this class and
  * use the generic store buffer interface.
  */
 class BufferableRef
 {
   public:
-    virtual bool match(void *location) = 0;
     virtual void mark(JSTracer *trc) = 0;
 };
 
 /*
  * HashKeyRef represents a reference to a HashTable key. Manual HashTable
  * barriers should should instantiate this template with their own table/key
  * type to insert into the generic buffer with putGeneric.
  */
@@ -90,29 +46,23 @@ class HashKeyRef : public BufferableRef
     Key key;
 
     typedef typename Map::Entry::ValueType ValueType;
     typedef typename Map::Ptr Ptr;
 
   public:
     HashKeyRef(Map *m, const Key &k) : map(m), key(k) {}
 
-    bool match(void *location) {
-        Ptr p = map->lookup(key);
-        if (!p)
-            return false;
-        return &p->key == location;
-    }
-
     void mark(JSTracer *trc) {
         Key prior = key;
         typename Map::Ptr p = map->lookup(key);
         if (!p)
             return;
         ValueType value = p->value;
+        JS_SET_TRACING_LOCATION(trc, (void*)&p->key);
         Mark(trc, &key, "HashKeyRef");
         if (prior != key) {
             map->remove(prior);
             map->put(key, value);
         }
     }
 };
 
@@ -165,18 +115,17 @@ class StoreBuffer
         void disable();
         void clear();
 
         bool isEmpty() const { return pos == base; }
         bool isFull() const { JS_ASSERT(pos <= top); return pos == top; }
         bool isAboutToOverflow() const { return pos >= highwater; }
 
         /* Compaction algorithms. */
-        template <typename NurseryType>
-        void compactNotInSet(NurseryType *nursery);
+        void compactNotInSet(const Nursery &nursery);
         void compactRemoveDuplicates();
 
         /*
          * Attempts to reduce the usage of the buffer by removing unnecessary
          * entries.
          */
         virtual void compact();
 
@@ -203,19 +152,16 @@ class StoreBuffer
                         clear();
                     }
                 }
             }
         }
 
         /* Mark the source of all edges in the store buffer. */
         void mark(JSTracer *trc);
-
-        /* For verification. */
-        bool accumulateEdges(EdgeSet &edges);
     };
 
     /*
      * Overrides the MonoTypeBuffer to support pointers that may be moved in
      * memory outside of the GC's control.
      */
     template <typename T>
     class RelocatableMonoTypeBuffer : public MonoTypeBuffer<T>
@@ -255,19 +201,16 @@ class StoreBuffer
 
         bool enable(uint8_t *region, size_t len);
         void disable();
         void clear();
 
         /* Mark all generic edges. */
         void mark(JSTracer *trc);
 
-        /* Check if a pointer is present in the buffer. */
-        bool containsEdge(void *location) const;
-
         template <typename T>
         void put(const T &t) {
             JS_ASSERT(!owner->inParallelSection());
 
             /* Check if we have been enabled. */
             if (!pos)
                 return;
 
@@ -295,19 +238,18 @@ class StoreBuffer
         Cell **edge;
 
         CellPtrEdge(Cell **v) : edge(v) {}
         bool operator==(const CellPtrEdge &other) const { return edge == other.edge; }
         bool operator!=(const CellPtrEdge &other) const { return edge != other.edge; }
 
         void *location() const { return (void *)edge; }
 
-        template <typename NurseryType>
-        bool inRememberedSet(NurseryType *nursery) const {
-            return !nursery->isInside(edge) && nursery->isInside(*edge);
+        bool inRememberedSet(const Nursery &nursery) const {
+            return !nursery.isInside(edge) && nursery.isInside(*edge);
         }
 
         bool isNullEdge() const {
             return !*edge;
         }
 
         void mark(JSTracer *trc);
 
@@ -326,19 +268,18 @@ class StoreBuffer
 
         ValueEdge(Value *v) : edge(v) {}
         bool operator==(const ValueEdge &other) const { return edge == other.edge; }
         bool operator!=(const ValueEdge &other) const { return edge != other.edge; }
 
         void *deref() const { return edge->isGCThing() ? edge->toGCThing() : NULL; }
         void *location() const { return (void *)edge; }
 
-        template <typename NurseryType>
-        bool inRememberedSet(NurseryType *nursery) const {
-            return !nursery->isInside(edge) && nursery->isInside(deref());
+        bool inRememberedSet(const Nursery &nursery) const {
+            return !nursery.isInside(edge) && nursery.isInside(deref());
         }
 
         bool isNullEdge() const {
             return !deref();
         }
 
         void mark(JSTracer *trc);
 
@@ -369,18 +310,17 @@ class StoreBuffer
         }
 
         JS_ALWAYS_INLINE HeapSlot *slotLocation() const;
 
         JS_ALWAYS_INLINE void *deref() const;
 
         JS_ALWAYS_INLINE void *location() const;
 
-        template <typename NurseryType>
-        JS_ALWAYS_INLINE bool inRememberedSet(NurseryType *nursery) const;
+        JS_ALWAYS_INLINE bool inRememberedSet(const Nursery &nursery) const;
 
         JS_ALWAYS_INLINE bool isNullEdge() const;
 
         void mark(JSTracer *trc);
     };
 
     class WholeCellEdges
     {
@@ -391,18 +331,17 @@ class StoreBuffer
 
         WholeCellEdges(Cell *cell) : tenured(cell) {
             JS_ASSERT(tenured->isTenured());
         }
 
         bool operator==(const WholeCellEdges &other) const { return tenured == other.tenured; }
         bool operator!=(const WholeCellEdges &other) const { return tenured != other.tenured; }
 
-        template <typename NurseryType>
-        bool inRememberedSet(NurseryType *nursery) const { return true; }
+        bool inRememberedSet(const Nursery &nursery) const { return true; }
 
         /* This is used by RemoveDuplicates as a unique pointer to this Edge. */
         void *location() const { return (void *)tenured; }
 
         bool isNullEdge() const { return false; }
 
         void mark(JSTracer *trc);
     };
@@ -418,19 +357,16 @@ class StoreBuffer
     JSRuntime *runtime;
 
     void *buffer;
 
     bool aboutToOverflow;
     bool overflowed;
     bool enabled;
 
-    /* For the verifier. */
-    EdgeSet edgeSet;
-
     /* TODO: profile to find the ideal size for these. */
     static const size_t ValueBufferSize = 1 * 1024 * sizeof(ValueEdge);
     static const size_t CellBufferSize = 2 * 1024 * sizeof(CellPtrEdge);
     static const size_t SlotBufferSize = 2 * 1024 * sizeof(SlotEdge);
     static const size_t WholeCellBufferSize = 2 * 1024 * sizeof(WholeCellEdges);
     static const size_t RelocValueBufferSize = 1 * 1024 * sizeof(ValueEdge);
     static const size_t RelocCellBufferSize = 1 * 1024 * sizeof(CellPtrEdge);
     static const size_t GenericBufferSize = 1 * 1024 * sizeof(int);
@@ -489,21 +425,16 @@ class StoreBuffer
     template <typename T>
     void putGeneric(const T &t) {
         bufferGeneric.put(t);
     }
 
     /* Mark the source of all edges in the store buffer. */
     void mark(JSTracer *trc);
 
-    /* For the verifier. */
-    bool coalesceForVerification();
-    void releaseVerificationData();
-    bool containsEdgeAt(void *loc) const;
-
     /* We cannot call InParallelSection directly because of a circular dependency. */
     bool inParallelSection() const;
 
     /* For use by our owned buffers and for testing. */
     void setAboutToOverflow();
     void setOverflowed();
 };
 
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -9,16 +9,18 @@
 #include "jscompartment.h"
 #include "jsgc.h"
 #include "jsprf.h"
 
 #include "js/HashTable.h"
 #include "gc/GCInternals.h"
 #include "gc/Zone.h"
 
+#include "jsgcinlines.h"
+
 #ifdef MOZ_VALGRIND
 # include <valgrind/memcheck.h>
 #endif
 
 using namespace js;
 using namespace js::gc;
 using namespace mozilla;
 
@@ -300,47 +302,16 @@ JS::CheckStackRoots(JSContext *cx)
     for (Rooter *p = rooters.begin(); p != rooters.end(); p++)
         p->rooter->scanned = true;
 }
 
 #endif /* DEBUG && JS_GC_ZEAL && JSGC_ROOT_ANALYSIS && !JS_THREADSAFE */
 
 #ifdef JS_GC_ZEAL
 
-static void
-DisableGGCForVerification(JSRuntime *rt)
-{
-#ifdef JSGC_GENERATIONAL
-    if (rt->gcVerifyPreData || rt->gcVerifyPostData)
-        return;
-
-    if (rt->gcNursery.isEnabled()) {
-        MinorGC(rt, JS::gcreason::API);
-        rt->gcNursery.disable();
-    }
-
-    if (rt->gcStoreBuffer.isEnabled())
-        rt->gcStoreBuffer.disable();
-#endif
-}
-
-static void
-EnableGGCAfterVerification(JSRuntime *rt)
-{
-#ifdef JSGC_GENERATIONAL
-    if (rt->gcVerifyPreData || rt->gcVerifyPostData)
-        return;
-
-    if (rt->gcGenerationalEnabled) {
-        rt->gcNursery.enable();
-        rt->gcStoreBuffer.enable();
-    }
-#endif
-}
-
 /*
  * Write barrier verification
  *
  * The next few functions are for write barrier verification.
  *
  * The VerifyBarriers function is a shorthand. It checks if a verification phase
  * is currently running. If not, it starts one. Otherwise, it ends the current
  * phase and starts a new one.
@@ -417,16 +388,18 @@ struct VerifyPreTracer : JSTracer {
  * This function builds up the heap snapshot by adding edges to the current
  * node.
  */
 static void
 AccumulateEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
 {
     VerifyPreTracer *trc = (VerifyPreTracer *)jstrc;
 
+    JS_ASSERT(!IsInsideNursery(trc->runtime, *(uintptr_t **)thingp));
+
     trc->edgeptr += sizeof(EdgeValue);
     if (trc->edgeptr >= trc->term) {
         trc->edgeptr = trc->term;
         return;
     }
 
     VerifyNode *node = trc->curnode;
     uint32_t i = node->count;
@@ -473,17 +446,17 @@ gc::StartVerifyPreBarriers(JSRuntime *rt
 {
     if (rt->gcVerifyPreData ||
         rt->gcIncrementalState != NO_INCREMENTAL ||
         !IsIncrementalGCSafe(rt))
     {
         return;
     }
 
-    DisableGGCForVerification(rt);
+    MinorGC(rt, JS::gcreason::API);
 
     AutoPrepareForTracing prep(rt);
 
     for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
         r.front()->bitmap.clear();
 
     VerifyPreTracer *trc = js_new<VerifyPreTracer>();
 
@@ -545,17 +518,16 @@ gc::StartVerifyPreBarriers(JSRuntime *rt
     }
 
     return;
 
 oom:
     rt->gcIncrementalState = NO_INCREMENTAL;
     js_delete(trc);
     rt->gcVerifyPreData = NULL;
-    EnableGGCAfterVerification(rt);
 }
 
 static bool
 IsMarkedOrAllocated(Cell *cell)
 {
     return cell->isMarked() || cell->arenaHeader()->allocatedDuringIncremental;
 }
 
@@ -650,28 +622,30 @@ gc::EndVerifyPreBarriers(JSRuntime *rt)
             node = NextNode(node);
         }
     }
 
     rt->gcMarker.reset();
     rt->gcMarker.stop();
 
     js_delete(trc);
-
-    EnableGGCAfterVerification(rt);
 }
 
 /*** Post-Barrier Verifyier ***/
 
 struct VerifyPostTracer : JSTracer {
     /* The gcNumber when the verification began. */
     uint64_t number;
 
     /* This counts up to gcZealFrequency to decide whether to verify. */
     int count;
+
+    /* The set of edges in the StoreBuffer at the end of verification. */
+    typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet;
+    EdgeSet *edges;
 };
 
 /*
  * The post-barrier verifier runs the full store buffer and a fake nursery when
  * running and when it stops, walks the full heap to ensure that all the
  * important edges were inserted into the storebuffer.
  */
 void
@@ -679,108 +653,124 @@ gc::StartVerifyPostBarriers(JSRuntime *r
 {
 #ifdef JSGC_GENERATIONAL
     if (rt->gcVerifyPostData ||
         rt->gcIncrementalState != NO_INCREMENTAL)
     {
         return;
     }
 
-    DisableGGCForVerification(rt);
+    MinorGC(rt, JS::gcreason::API);
 
     VerifyPostTracer *trc = js_new<VerifyPostTracer>();
     rt->gcVerifyPostData = trc;
     rt->gcNumber++;
     trc->number = rt->gcNumber;
     trc->count = 0;
-
-    if (!rt->gcVerifierNursery.enable())
-        goto oom;
-
-    if (!rt->gcStoreBuffer.enable())
-        goto oom;
-
-    return;
-oom:
-    js_delete(trc);
-    rt->gcVerifyPostData = NULL;
-    EnableGGCAfterVerification(rt);
 #endif
 }
 
 #ifdef JSGC_GENERATIONAL
+void
+PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
+{
+    VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
+
+    /* The nursery only stores objects. */
+    if (kind != JSTRACE_OBJECT)
+        return;
+
+    /* The store buffer may store extra, non-cross-generational edges. */
+    JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
+    if (trc->runtime->gcNursery.isInside(thingp) || !trc->runtime->gcNursery.isInside(dst))
+        return;
+
+    /*
+     * Values will be unpacked to the stack before getting here. However, the
+     * only things that enter this callback are marked by the store buffer. The
+     * store buffer ensures that the real tracing location is set correctly.
+     */
+    void **loc = trc->realLocation != NULL ? (void **)trc->realLocation : thingp;
+
+    trc->edges->put(loc);
+}
+
 static void
-AssertStoreBufferContainsEdge(StoreBuffer *storebuf, void *loc, void *dst)
+AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet *edges, void **loc, JSObject *dst)
 {
-    if (storebuf->containsEdgeAt(loc))
+    if (edges->has(loc))
         return;
 
     char msgbuf[1024];
     JS_snprintf(msgbuf, sizeof(msgbuf), "[post-barrier verifier] Missing edge @ %p to %p",
-                loc, dst);
+                (void *)loc, (void *)dst);
     MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
     MOZ_CRASH();
 }
 
 void
 PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind)
 {
     VerifyPostTracer *trc = (VerifyPostTracer *)jstrc;
-    Cell *dst = (Cell *)*thingp;
-    JSRuntime *rt = dst->runtime();
+
+    /* The nursery only stores objects. */
+    if (kind != JSTRACE_OBJECT)
+        return;
 
     /* Filter out non cross-generational edges. */
-    if (!rt->gcVerifierNursery.isInside(dst))
+    JS_ASSERT(!trc->runtime->gcNursery.isInside(thingp));
+    JSObject *dst = *reinterpret_cast<JSObject **>(thingp);
+    if (!trc->runtime->gcNursery.isInside(dst))
         return;
 
     /*
-     * Note: since Value travels through the stack to get Cell**, we need to use
-     * the annotated location in the tracer instead of the indirect location for
-     * these edges.
+     * Values will be unpacked to the stack before getting here. However, the
+     * only things that enter this callback are marked by the JS_TraceChildren
+     * below. Since ObjectImpl::markChildren handles this, the real trace
+     * location will be set correctly in these cases.
      */
-    Cell *loc = (Cell *)(trc->realLocation != NULL ? trc->realLocation : thingp);
+    void **loc = trc->realLocation != NULL ? (void **)trc->realLocation : thingp;
 
-    AssertStoreBufferContainsEdge(&rt->gcStoreBuffer, loc, dst);
+    AssertStoreBufferContainsEdge(trc->edges, loc, dst);
 }
 #endif
 
 void
 js::gc::EndVerifyPostBarriers(JSRuntime *rt)
 {
 #ifdef JSGC_GENERATIONAL
+    VerifyPostTracer::EdgeSet edges;
     AutoPrepareForTracing prep(rt);
 
     VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData;
-    JS_TracerInit(trc, rt, PostVerifierVisitEdge);
-    trc->count = 0;
 
     if (rt->gcStoreBuffer.hasOverflowed())
         goto oom;
 
-    if (!rt->gcStoreBuffer.coalesceForVerification())
+    /* Visit every entry in the store buffer and put the edges in a hash set. */
+    JS_TracerInit(trc, rt, PostVerifierCollectStoreBufferEdges);
+    if (!edges.init())
         goto oom;
+    trc->edges = &edges;
+    rt->gcStoreBuffer.mark(trc);
 
-    /* Walk the heap. */
+    /* Walk the heap to find any edges not the the |edges| set. */
+    JS_TracerInit(trc, rt, PostVerifierVisitEdge);
     for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) {
         for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) {
             for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) {
                 Cell *src = cells.getCell();
-                if (!rt->gcVerifierNursery.isInside(src))
-                    JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind)));
+                JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind)));
             }
         }
     }
 
 oom:
     js_delete(trc);
     rt->gcVerifyPostData = NULL;
-    rt->gcVerifierNursery.disable();
-    rt->gcStoreBuffer.disable();
-    rt->gcStoreBuffer.releaseVerificationData();
-    EnableGGCAfterVerification(rt);
 #endif
 }
 
 /*** Barrier Verifier Scheduling ***/
 
 static void
 VerifyPreBarriers(JSRuntime *rt)
 {
@@ -856,18 +846,14 @@ js::gc::FinishVerifier(JSRuntime *rt)
 {
     if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) {
         js_delete(trc);
         rt->gcVerifyPreData = NULL;
     }
 #ifdef JSGC_GENERATIONAL
     if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) {
         js_delete(trc);
-        rt->gcVerifierNursery.disable();
-        rt->gcStoreBuffer.disable();
-        rt->gcStoreBuffer.releaseVerificationData();
         rt->gcVerifyPostData = NULL;
     }
 #endif
-    EnableGGCAfterVerification(rt);
 }
 
 #endif /* JS_GC_ZEAL */
--- a/js/src/ion/BaselineBailouts.cpp
+++ b/js/src/ion/BaselineBailouts.cpp
@@ -1210,17 +1210,17 @@ ion::FinishBailoutToBaseline(BaselineBai
     if (topFrame->scopeChain() && !EnsureHasScopeObjects(cx, topFrame))
         return false;
 
     // Create arguments objects for bailed out frames, to maintain the invariant
     // that script->needsArgsObj() implies frame->hasArgsObj().
     RootedScript innerScript(cx, NULL);
     RootedScript outerScript(cx, NULL);
 
-    JS_ASSERT(cx->mainThread().currentlyRunningInJit());
+    JS_ASSERT(cx->currentlyRunningInJit());
     IonFrameIterator iter(cx->mainThread().ionTop);
 
     uint32_t frameno = 0;
     while (frameno < numFrames) {
         JS_ASSERT(!iter.isOptimizedJS());
 
         if (iter.isBaselineJS()) {
             BaselineFrame *frame = iter.baselineFrame();
--- a/js/src/ion/BaselineFrame.h
+++ b/js/src/ion/BaselineFrame.h
@@ -145,30 +145,30 @@ class BaselineFrame
         JS_ASSERT((size % sizeof(Value)) == 0);
         return size / sizeof(Value);
     }
     Value *valueSlot(size_t slot) const {
         JS_ASSERT(slot < numValueSlots());
         return (Value *)this - (slot + 1);
     }
 
-    Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing) const {
+    Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i));
         JS_ASSERT(i < script()->nfixed);
         return *valueSlot(i);
     }
 
-    Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing) const {
+    Value &unaliasedFormal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT(i < numFormalArgs());
         JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
         JS_ASSERT_IF(checkAliasing, !script()->formalIsAliased(i));
         return argv()[i];
     }
 
-    Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing) const {
+    Value &unaliasedActual(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
         JS_ASSERT(i < numActualArgs());
         JS_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
         JS_ASSERT_IF(checkAliasing && i < numFormalArgs(), !script()->formalIsAliased(i));
         return argv()[i];
     }
 
     Value &unaliasedLocal(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const {
 #ifdef DEBUG
@@ -332,16 +332,19 @@ class BaselineFrame
         return isNonStrictEvalFrame() && isDirectEvalFrame();
     }
     bool isNonEvalFunctionFrame() const {
         return isFunctionFrame() && !isEvalFrame();
     }
     bool isDebuggerFrame() const {
         return false;
     }
+    bool isGeneratorFrame() const {
+        return false;
+    }
 
     IonJSFrameLayout *framePrefix() const {
         uint8_t *fp = (uint8_t *)this + Size() + FramePointerOffset;
         return (IonJSFrameLayout *)fp;
     }
 
     // Methods below are used by the compiler.
     static size_t offsetOfCalleeToken() {
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -671,17 +671,17 @@ ICStubCompiler::emitPostWriteBarrierSlot
 #endif // JSGC_GENERATIONAL
 
 //
 // UseCount_Fallback
 //
 static bool
 IsTopFrameConstructing(JSContext *cx)
 {
-    JS_ASSERT(cx->mainThread().currentlyRunningInJit());
+    JS_ASSERT(cx->currentlyRunningInJit());
     JitActivationIterator activations(cx->runtime());
     IonFrameIterator iter(activations);
     JS_ASSERT(iter.type() == IonFrame_Exit);
 
     ++iter;
     JS_ASSERT(iter.type() == IonFrame_BaselineStub);
 
     ++iter;
@@ -2463,16 +2463,19 @@ DoBinaryArithFallback(JSContext *cx, Bas
             return false;
         break;
       }
       default:
         JS_NOT_REACHED("Unhandled baseline arith op");
         return false;
     }
 
+    if (ret.isDouble())
+        stub->setSawDoubleResult();
+
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
         // But for now we just bail.
         return true;
     }
 
     // Handle string concat.
@@ -2965,16 +2968,19 @@ DoUnaryArithFallback(JSContext *cx, Base
         if (!NegOperation(cx, script, pc, val, res))
             return false;
         break;
       default:
         JS_NOT_REACHED("Unexpected op");
         return false;
     }
 
+    if (res.isDouble())
+        stub->setSawDoubleResult();
+
     if (stub->numOptimizedStubs() >= ICUnaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard/replace stubs.
         return true;
     }
 
     if (val.isInt32() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
         ICUnaryArith_Int32::Compiler compiler(cx, op);
--- a/js/src/ion/BaselineIC.h
+++ b/js/src/ion/BaselineIC.h
@@ -2370,27 +2370,37 @@ class ICToNumber_Fallback : public ICFal
 //      JSOP_BITAND, JSOP_BITXOR, JSOP_BITOR
 //      JSOP_LSH, JSOP_RSH, JSOP_URSH
 
 class ICBinaryArith_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     ICBinaryArith_Fallback(IonCode *stubCode)
-      : ICFallbackStub(BinaryArith_Fallback, stubCode) {}
+      : ICFallbackStub(BinaryArith_Fallback, stubCode)
+    {
+        extra_ = 0;
+    }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICBinaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
         if (!code)
             return NULL;
         return space->allocate<ICBinaryArith_Fallback>(code);
     }
 
+    bool sawDoubleResult() {
+        return extra_;
+    }
+    void setSawDoubleResult() {
+        extra_ = 1;
+    }
+
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::BinaryArith_Fallback) {}
@@ -2658,27 +2668,37 @@ class ICBinaryArith_DoubleWithInt32 : pu
 //     JSOP_BITNOT
 //     JSOP_NEG
 
 class ICUnaryArith_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     ICUnaryArith_Fallback(IonCode *stubCode)
-      : ICFallbackStub(UnaryArith_Fallback, stubCode) {}
+      : ICFallbackStub(UnaryArith_Fallback, stubCode)
+    {
+        extra_ = 0;
+    }
 
   public:
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICUnaryArith_Fallback *New(ICStubSpace *space, IonCode *code) {
         if (!code)
             return NULL;
         return space->allocate<ICUnaryArith_Fallback>(code);
     }
 
+    bool sawDoubleResult() {
+        return extra_;
+    }
+    void setSawDoubleResult() {
+        extra_ = 1;
+    }
+
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
       public:
         Compiler(JSContext *cx)
           : ICStubCompiler(cx, ICStub::UnaryArith_Fallback)
--- a/js/src/ion/BaselineInspector.cpp
+++ b/js/src/ion/BaselineInspector.cpp
@@ -160,19 +160,19 @@ BaselineInspector::expectedResultType(js
 
     switch (stub->kind()) {
       case ICStub::BinaryArith_Int32:
         if (stub->toBinaryArith_Int32()->allowDouble())
             return MIRType_Double;
         return MIRType_Int32;
       case ICStub::BinaryArith_BooleanWithInt32:
       case ICStub::UnaryArith_Int32:
+      case ICStub::BinaryArith_DoubleWithInt32:
         return MIRType_Int32;
       case ICStub::BinaryArith_Double:
-      case ICStub::BinaryArith_DoubleWithInt32:
       case ICStub::UnaryArith_Double:
         return MIRType_Double;
       case ICStub::BinaryArith_StringConcat:
       case ICStub::BinaryArith_StringObjectConcat:
         return MIRType_String;
       default:
         return MIRType_None;
     }
@@ -306,8 +306,27 @@ BaselineInspector::hasSeenAccessedGetter
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
         return stub->toGetProp_Fallback()->hasAccessedGetter();
     return false;
 }
+
+bool
+BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
+{
+    if (!hasBaselineScript())
+        return false;
+
+    const ICEntry &entry = icEntryFromPC(pc);
+    ICStub *stub = entry.fallbackStub();
+
+    JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
+
+    if (stub->isUnaryArith_Fallback())
+        return stub->toUnaryArith_Fallback()->sawDoubleResult();
+    else
+        return stub->toBinaryArith_Fallback()->sawDoubleResult();
+
+    return false;
+}
--- a/js/src/ion/BaselineInspector.h
+++ b/js/src/ion/BaselineInspector.h
@@ -103,16 +103,17 @@ class BaselineInspector
     }
 
     MIRType expectedResultType(jsbytecode *pc);
     MCompare::CompareType expectedCompareType(jsbytecode *pc);
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
+    bool hasSeenDoubleResult(jsbytecode *pc);
 };
 
 } // namespace ion
 } // namespace js
 
 #endif // JS_ION
 
 #endif // jsion_baseline_inspector_h__
--- a/js/src/ion/BaselineJIT.cpp
+++ b/js/src/ion/BaselineJIT.cpp
@@ -38,151 +38,162 @@ BaselineScript::BaselineScript(uint32_t 
 #ifdef DEBUG
     spsOn_(false),
 #endif
     spsPushToggleOffset_(spsPushToggleOffset),
     flags_(0)
 { }
 
 static const size_t BASELINE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4096;
+static const unsigned BASELINE_MAX_ARGS_LENGTH = 20000;
 
 static bool
 CheckFrame(StackFrame *fp)
 {
     if (fp->isGeneratorFrame()) {
         IonSpew(IonSpew_BaselineAbort, "generator frame");
         return false;
     }
 
     if (fp->isDebuggerFrame()) {
         // Debugger eval-in-frame. These are likely short-running scripts so
         // don't bother compiling them for now.
         IonSpew(IonSpew_BaselineAbort, "debugger frame");
         return false;
     }
 
-    static const unsigned MAX_ARGS_LENGTH = 20000;
-
-    if (fp->isNonEvalFunctionFrame() && fp->numActualArgs() > MAX_ARGS_LENGTH) {
+    if (fp->isNonEvalFunctionFrame() && fp->numActualArgs() > BASELINE_MAX_ARGS_LENGTH) {
         // Fall back to the interpreter to avoid running out of stack space.
         IonSpew(IonSpew_BaselineAbort, "Too many arguments (%u)", fp->numActualArgs());
         return false;
     }
 
     return true;
 }
 
 static bool
 IsJSDEnabled(JSContext *cx)
 {
     return cx->compartment()->debugMode() && cx->runtime()->debugHooks.callHook;
 }
 
 static IonExecStatus
-EnterBaseline(JSContext *cx, StackFrame *fp, void *jitcode, bool osr)
+EnterBaseline(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsBaselineEnabled(cx));
-    JS_ASSERT(CheckFrame(fp));
+    JS_ASSERT_IF(data.osrFrame, CheckFrame(data.osrFrame));
 
     EnterIonCode enter = cx->compartment()->ionCompartment()->enterBaselineJIT();
 
-    // maxArgc is the maximum of arguments between the number of actual
-    // arguments and the number of formal arguments. It accounts for |this|.
-    int maxArgc = 0;
-    Value *maxArgv = NULL;
-    unsigned numActualArgs = 0;
-    RootedValue thisv(cx);
+    // Caller must construct |this| before invoking the Ion function.
+    JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
 
-    void *calleeToken;
-    if (fp->isNonEvalFunctionFrame()) {
-        numActualArgs = fp->numActualArgs();
-        maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
-        maxArgv = fp->argv() - 1; // -1 = include |this|
-        calleeToken = CalleeToToken(&fp->callee());
-    } else {
-        // For eval function frames, set the callee token to the enclosing function.
-        if (fp->isFunctionFrame())
-            calleeToken = CalleeToToken(&fp->callee());
-        else
-            calleeToken = CalleeToToken(fp->script());
-        thisv = fp->thisValue();
-        maxArgc = 1;
-        maxArgv = thisv.address();
-    }
-
-    // Caller must construct |this| before invoking the Ion function.
-    JS_ASSERT_IF(fp->isConstructing(), fp->functionThis().isObject());
-
-    RootedValue result(cx, Int32Value(numActualArgs));
+    data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
-        JitActivation activation(cx, fp->isConstructing());
+        JitActivation activation(cx, data.constructing);
         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
-
-        fp->setRunningInJit();
+        AutoFlushInhibitor afi(cx->compartment()->ionCompartment());
 
-        // Pass the scope chain for global and eval frames.
-        JSObject *scopeChain = NULL;
-        if (!fp->isNonEvalFunctionFrame())
-            scopeChain = fp->scopeChain();
+        if (data.osrFrame)
+            data.osrFrame->setRunningInJit();
 
-        // For OSR, pass the number of locals + stack values.
-        uint32_t numStackValues = osr ? fp->script()->nfixed + cx->regs().stackDepth() : 0;
-        JS_ASSERT_IF(osr, !IsJSDEnabled(cx));
+        JS_ASSERT_IF(data.osrFrame, !IsJSDEnabled(cx));
 
-        AutoFlushInhibitor afi(cx->compartment()->ionCompartment());
         // Single transition point from Interpreter to Baseline.
-        enter(jitcode, maxArgc, maxArgv, osr ? fp : NULL, calleeToken, scopeChain, numStackValues,
-              result.address());
+        enter(data.jitcode, data.maxArgc, data.maxArgv, data.osrFrame, data.calleeToken,
+              data.scopeChain, data.osrNumStackValues, data.result.address());
 
-        fp->clearRunningInJit();
+        if (data.osrFrame)
+            data.osrFrame->clearRunningInJit();
     }
 
-    JS_ASSERT(fp == cx->fp());
     JS_ASSERT(!cx->runtime()->hasIonReturnOverride());
 
-    // The trampoline wrote the return value but did not set the HAS_RVAL flag.
-    fp->setReturnValue(result);
-
-    // Ion callers wrap primitive constructor return.
-    if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive())
-        fp->setReturnValue(ObjectValue(fp->constructorThis()));
+    // Jit callers wrap primitive constructor return.
+    if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
+        data.result = data.maxArgv[0];
 
     // Release temporary buffer used for OSR into Ion.
     cx->runtime()->getIonRuntime(cx)->freeOsrTempData();
 
-    JS_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR));
-    return result.isMagic() ? IonExec_Error : IonExec_Ok;
+    JS_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR));
+    return data.result.isMagic() ? IonExec_Error : IonExec_Ok;
 }
 
 IonExecStatus
-ion::EnterBaselineMethod(JSContext *cx, StackFrame *fp)
+ion::EnterBaselineMethod(JSContext *cx, RunState &state)
 {
-    BaselineScript *baseline = fp->script()->baselineScript();
-    void *jitcode = baseline->method()->raw();
+    BaselineScript *baseline = state.script()->baselineScript();
+
+    EnterJitData data(cx);
+    data.jitcode = baseline->method()->raw();
 
-    return EnterBaseline(cx, fp, jitcode, /* osr = */false);
+    AutoValueVector vals(cx);
+    if (!SetEnterJitData(cx, data, state, vals))
+        return IonExec_Error;
+
+    IonExecStatus status = EnterBaseline(cx, data);
+    if (status != IonExec_Ok)
+        return status;
+
+    state.setReturnValue(data.result);
+    return IonExec_Ok;
 }
 
 IonExecStatus
 ion::EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc)
 {
     JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY);
 
     BaselineScript *baseline = fp->script()->baselineScript();
-    uint8_t *jitcode = baseline->nativeCodeForPC(fp->script(), pc);
+
+    EnterJitData data(cx);
+    data.jitcode = baseline->nativeCodeForPC(fp->script(), pc);
 
     // Skip debug breakpoint/trap handler, the interpreter already handled it
     // for the current op.
     if (cx->compartment()->debugMode())
-        jitcode += MacroAssembler::ToggledCallSize();
+        data.jitcode += MacroAssembler::ToggledCallSize();
+
+    data.osrFrame = fp;
+    data.osrNumStackValues = fp->script()->nfixed + cx->interpreterRegs().stackDepth();
+
+    RootedValue thisv(cx);
 
-    return EnterBaseline(cx, fp, jitcode, /* osr = */true);
+    if (fp->isNonEvalFunctionFrame()) {
+        data.constructing = fp->isConstructing();
+        data.numActualArgs = fp->numActualArgs();
+        data.maxArgc = Max(fp->numActualArgs(), fp->numFormalArgs()) + 1; // +1 = include |this|
+        data.maxArgv = fp->argv() - 1; // -1 = include |this|
+        data.scopeChain = NULL;
+        data.calleeToken = CalleeToToken(&fp->callee());
+    } else {
+        thisv = fp->thisValue();
+        data.constructing = false;
+        data.numActualArgs = 0;
+        data.maxArgc = 1;
+        data.maxArgv = thisv.address();
+        data.scopeChain = fp->scopeChain();
+
+        // For eval function frames, set the callee token to the enclosing function.
+        if (fp->isFunctionFrame())
+            data.calleeToken = CalleeToToken(&fp->callee());
+        else
+            data.calleeToken = CalleeToToken(fp->script());
+    }
+
+    IonExecStatus status = EnterBaseline(cx, data);
+    if (status != IonExec_Ok)
+        return status;
+
+    fp->setReturnValue(data.result);
+    return IonExec_Ok;
 }
 
 static MethodStatus
 BaselineCompile(JSContext *cx, HandleScript script)
 {
     JS_ASSERT(!script->hasBaselineScript());
     JS_ASSERT(script->canBaselineCompile());
 
@@ -205,54 +216,39 @@ BaselineCompile(JSContext *cx, HandleScr
     JS_ASSERT_IF(status != Method_Compiled, !script->hasBaselineScript());
 
     if (status == Method_CantCompile)
         script->setBaselineScript(BASELINE_DISABLED_SCRIPT);
 
     return status;
 }
 
-MethodStatus
-ion::CanEnterBaselineJIT(JSContext *cx, JSScript *scriptArg, StackFrame *fp, bool newType)
+static MethodStatus
+CanEnterBaselineJIT(JSContext *cx, HandleScript script, bool osr)
 {
-    // Skip if baseline compilation is disabled in options.
     JS_ASSERT(ion::IsBaselineEnabled(cx));
 
     // Skip if the script has been disabled.
-    if (!scriptArg->canBaselineCompile())
+    if (!script->canBaselineCompile())
         return Method_Skipped;
 
-    if (scriptArg->length > BaselineScript::MAX_JSSCRIPT_LENGTH)
-        return Method_CantCompile;
-
-    RootedScript script(cx, scriptArg);
-
-    // If constructing, allocate a new |this| object.
-    if (fp->isConstructing() && fp->functionThis().isPrimitive()) {
-        RootedObject callee(cx, &fp->callee());
-        RootedObject obj(cx, CreateThisForFunction(cx, callee, newType));
-        if (!obj)
-            return Method_Skipped;
-        fp->functionThis().setObject(*obj);
-    }
-
-    if (!CheckFrame(fp))
+    if (script->length > BaselineScript::MAX_JSSCRIPT_LENGTH)
         return Method_CantCompile;
 
     if (!cx->compartment()->ensureIonCompartmentExists(cx))
         return Method_Error;
 
     if (script->hasBaselineScript())
         return Method_Compiled;
 
     // Check script use count. However, always eagerly compile scripts if JSD
     // is enabled, so that we don't have to OSR and don't have to update the
     // frame pointer stored in JSD's frames list.
     if (IsJSDEnabled(cx)) {
-        if (JSOp(*cx->regs().pc) == JSOP_LOOPENTRY) // No OSR.
+        if (osr)
             return Method_Skipped;
     } else if (script->incUseCount() <= js_IonOptions.baselineUsesBeforeCompile) {
         return Method_Skipped;
     }
 
     if (script->isCallsiteClone) {
         // Ensure the original function is compiled too, so that bailouts from
         // Ion code have a BaselineScript to resume into.
@@ -267,16 +263,70 @@ ion::CanEnterBaselineJIT(JSContext *cx, 
             if (status != Method_Compiled)
                 return status;
         }
     }
 
     return BaselineCompile(cx, script);
 }
 
+MethodStatus
+ion::CanEnterBaselineAtBranch(JSContext *cx, StackFrame *fp, bool newType)
+{
+   // If constructing, allocate a new |this| object.
+   if (fp->isConstructing() && fp->functionThis().isPrimitive()) {
+       RootedObject callee(cx, &fp->callee());
+       RootedObject obj(cx, CreateThisForFunction(cx, callee, newType));
+       if (!obj)
+           return Method_Skipped;
+       fp->functionThis().setObject(*obj);
+   }
+
+   if (!CheckFrame(fp))
+       return Method_CantCompile;
+
+   RootedScript script(cx, fp->script());
+   return CanEnterBaselineJIT(cx, script, /* osr = */true);
+}
+
+MethodStatus
+ion::CanEnterBaselineMethod(JSContext *cx, RunState &state)
+{
+    if (state.isInvoke()) {
+        InvokeState &invoke = *state.asInvoke();
+
+        if (invoke.args().length() > BASELINE_MAX_ARGS_LENGTH) {
+            IonSpew(IonSpew_BaselineAbort, "Too many arguments (%u)", invoke.args().length());
+            return Method_CantCompile;
+        }
+
+        // If constructing, allocate a new |this| object.
+        if (invoke.constructing() && invoke.args().thisv().isPrimitive()) {
+            RootedObject callee(cx, &invoke.args().callee());
+            RootedObject obj(cx, CreateThisForFunction(cx, callee, invoke.useNewType()));
+            if (!obj)
+                return Method_Skipped;
+            invoke.args().setThis(ObjectValue(*obj));
+        }
+    } else if (state.isExecute()) {
+        ExecuteType type = state.asExecute()->type();
+        if (type == EXECUTE_DEBUG || type == EXECUTE_DEBUG_GLOBAL) {
+            IonSpew(IonSpew_BaselineAbort, "debugger frame");
+            return Method_CantCompile;
+        }
+    } else {
+        JS_ASSERT(state.isGenerator());
+        IonSpew(IonSpew_BaselineAbort, "generator frame");
+        return Method_CantCompile;
+    }
+
+    RootedScript script(cx, state.script());
+    return CanEnterBaselineJIT(cx, script, /* osr = */false);
+};
+
 // Be safe, align IC entry list to 8 in all cases.
 static const unsigned DataAlignment = sizeof(uintptr_t);
 
 BaselineScript *
 BaselineScript::New(JSContext *cx, uint32_t prologueOffset,
                     uint32_t spsPushToggleOffset, size_t icEntries,
                     size_t pcMappingIndexEntries, size_t pcMappingSize)
 {
--- a/js/src/ion/BaselineJIT.h
+++ b/js/src/ion/BaselineJIT.h
@@ -258,20 +258,23 @@ struct BaselineScript
 
 inline bool
 IsBaselineEnabled(JSContext *cx)
 {
     return cx->hasOption(JSOPTION_BASELINE);
 }
 
 MethodStatus
-CanEnterBaselineJIT(JSContext *cx, JSScript *scriptArg, StackFrame *fp, bool newType);
+CanEnterBaselineMethod(JSContext *cx, RunState &state);
+
+MethodStatus
+CanEnterBaselineAtBranch(JSContext *cx, StackFrame *fp, bool newType);
 
 IonExecStatus
-EnterBaselineMethod(JSContext *cx, StackFrame *fp);
+EnterBaselineMethod(JSContext *cx, RunState &state);
 
 IonExecStatus
 EnterBaselineAtBranch(JSContext *cx, StackFrame *fp, jsbytecode *pc);
 
 void
 FinishDiscardBaselineScript(FreeOp *fop, JSScript *script);
 
 void
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1337,17 +1337,17 @@ OffThreadCompilationAvailable(JSContext 
     return OffThreadCompilationEnabled(cx)
         && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL
         && !cx->runtime()->profilingScripts
         && !cx->runtime()->spsProfiler.enabled();
 }
 
 static AbortReason
 IonCompile(JSContext *cx, JSScript *script,
-           AbstractFramePtr fp, jsbytecode *osrPc, bool constructing,
+           BaselineFrame *baselineFrame, jsbytecode *osrPc, bool constructing,
            ExecutionMode executionMode)
 {
 #if JS_TRACE_LOGGING
     AutoTraceLog logger(TraceLogging::defaultLogger(),
                         TraceLogging::ION_COMPILE_START,
                         TraceLogging::ION_COMPILE_STOP,
                         script);
 #endif
@@ -1386,22 +1386,22 @@ IonCompile(JSContext *cx, JSScript *scri
     AutoFlushCache afc("IonCompile");
 
     types::AutoEnterCompilation enterCompiler(cx, CompilerOutputKind(executionMode));
     if (!enterCompiler.init(script))
         return AbortReason_Disable;
 
     AutoTempAllocatorRooter root(cx, temp);
 
-    IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, fp);
+    IonBuilder *builder = alloc->new_<IonBuilder>(cx, temp, graph, &inspector, info, baselineFrame);
     if (!builder)
         return AbortReason_Alloc;
 
     JS_ASSERT(!GetIonScript(builder->script(), executionMode));
-    JS_ASSERT(builder->script()->canIonCompile());
+    JS_ASSERT(CanIonCompile(builder->script(), executionMode));
 
     RootedScript builderScript(cx, builder->script());
     IonSpewNewFunction(graph, builderScript);
 
     if (!builder->build()) {
         IonSpew(IonSpew_Abort, "Builder failed to build.");
         return builder->abortReason();
     }
@@ -1432,53 +1432,47 @@ IonCompile(JSContext *cx, JSScript *scri
     bool success = codegen->link();
 
     IonSpewEndFunction();
 
     return success ? AbortReason_NoAbort : AbortReason_Disable;
 }
 
 static bool
-CheckFrame(AbstractFramePtr fp)
+TooManyArguments(unsigned nargs)
 {
-    if (fp.isEvalFrame()) {
-        // Eval frames are not yet supported. Supporting this will require new
-        // logic in pushBailoutFrame to deal with linking prev.
-        // Additionally, JSOP_DEFVAR support will require baking in isEvalFrame().
-        IonSpew(IonSpew_Abort, "eval frame");
-        return false;
-    }
-
-    if (fp.isGeneratorFrame()) {
-        // Err... no.
-        IonSpew(IonSpew_Abort, "generator frame");
-        return false;
-    }
-
-    if (fp.isDebuggerFrame()) {
-        IonSpew(IonSpew_Abort, "debugger frame");
-        return false;
-    }
-
-    // This check is to not overrun the stack. Eventually, we will want to
-    // handle this when we support JSOP_ARGUMENTS or function calls.
-    if (fp.isFunctionFrame() &&
-        (fp.numActualArgs() >= SNAPSHOT_MAX_NARGS ||
-         fp.numActualArgs() > js_IonOptions.maxStackArgs))
-    {
+    return (nargs >= SNAPSHOT_MAX_NARGS || nargs > js_IonOptions.maxStackArgs);
+}
+
+static bool
+CheckFrame(BaselineFrame *frame)
+{
+    JS_ASSERT(!frame->isGeneratorFrame());
+    JS_ASSERT(!frame->isDebuggerFrame());
+
+    // This check is to not overrun the stack.
+    if (frame->isFunctionFrame() && TooManyArguments(frame->numActualArgs())) {
         IonSpew(IonSpew_Abort, "too many actual args");
         return false;
     }
 
     return true;
 }
 
 static bool
 CheckScript(JSContext *cx, JSScript *script, bool osr)
 {
+    if (script->isForEval()) {
+        // Eval frames are not yet supported. Supporting this will require new
+        // logic in pushBailoutFrame to deal with linking prev.
+        // Additionally, JSOP_DEFVAR support will require baking in isEvalFrame().
+        IonSpew(IonSpew_Abort, "eval script");
+        return false;
+    }
+
     if (!script->analyzedArgsUsage() && !script->ensureRanAnalysis(cx)) {
         IonSpew(IonSpew_Abort, "OOM under ensureRanAnalysis");
         return false;
     }
 
     if (osr && script->needsArgsObj()) {
         // OSR-ing into functions with arguments objects is not supported.
         IonSpew(IonSpew_Abort, "OSR script has argsobj");
@@ -1541,17 +1535,17 @@ CanIonCompileScript(JSContext *cx, Handl
 {
     if (!script->canIonCompile() || !CheckScript(cx, script, osr))
         return false;
 
     return CheckScriptSize(cx, script) == Method_Compiled;
 }
 
 static MethodStatus
-Compile(JSContext *cx, HandleScript script, AbstractFramePtr fp, jsbytecode *osrPc,
+Compile(JSContext *cx, HandleScript script, BaselineFrame *osrFrame, jsbytecode *osrPc,
         bool constructing, ExecutionMode executionMode)
 {
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT(ion::IsBaselineEnabled(cx));
     JS_ASSERT_IF(osrPc != NULL, (JSOp)*osrPc == JSOP_LOOPENTRY);
 
     if (executionMode == SequentialExecution && !script->hasBaselineScript())
         return Method_Skipped;
@@ -1581,31 +1575,31 @@ Compile(JSContext *cx, HandleScript scri
 
     if (executionMode == SequentialExecution) {
         // Use getUseCount instead of incUseCount to avoid bumping the
         // use count twice.
         if (script->getUseCount() < js_IonOptions.usesBeforeCompile)
             return Method_Skipped;
     }
 
-    AbortReason reason = IonCompile(cx, script, fp, osrPc, constructing, executionMode);
+    AbortReason reason = IonCompile(cx, script, osrFrame, osrPc, constructing, executionMode);
     if (reason == AbortReason_Disable)
         return Method_CantCompile;
 
     // Compilation succeeded or we invalidated right away or an inlining/alloc abort
     return HasIonScript(script, executionMode) ? Method_Compiled : Method_Skipped;
 }
 
 } // namespace ion
 } // namespace js
 
 // Decide if a transition from interpreter execution to Ion code should occur.
 // May compile or recompile the target JSScript.
 MethodStatus
-ion::CanEnterAtBranch(JSContext *cx, JSScript *script, AbstractFramePtr fp,
+ion::CanEnterAtBranch(JSContext *cx, JSScript *script, BaselineFrame *osrFrame,
                       jsbytecode *pc, bool isConstructing)
 {
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT((JSOp)*pc == JSOP_LOOPENTRY);
 
     // Skip if the script has been disabled.
     if (!script->canIonCompile())
         return Method_Skipped;
@@ -1618,24 +1612,24 @@ ion::CanEnterAtBranch(JSContext *cx, JSS
     if (script->hasIonScript() && script->ionScript()->bailoutExpected())
         return Method_Skipped;
 
     // Optionally ignore on user request.
     if (!js_IonOptions.osr)
         return Method_Skipped;
 
     // Mark as forbidden if frame can't be handled.
-    if (!CheckFrame(fp)) {
+    if (!CheckFrame(osrFrame)) {
         ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
     // Attempt compilation. Returns Method_Compiled if already compiled.
     RootedScript rscript(cx, script);
-    MethodStatus status = Compile(cx, rscript, fp, pc, isConstructing, SequentialExecution);
+    MethodStatus status = Compile(cx, rscript, osrFrame, pc, isConstructing, SequentialExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
     if (script->ionScript()->osrPc() != pc) {
         // If we keep failing to enter the script due to an OSR pc mismatch,
@@ -1650,88 +1644,100 @@ ion::CanEnterAtBranch(JSContext *cx, JSS
     }
 
     script->ionScript()->resetOsrPcMismatchCounter();
 
     return Method_Compiled;
 }
 
 MethodStatus
-ion::CanEnter(JSContext *cx, HandleScript script, AbstractFramePtr fp, bool isConstructing)
+ion::CanEnter(JSContext *cx, RunState &state)
 {
     JS_ASSERT(ion::IsEnabled(cx));
 
+    JSScript *script = state.script();
+
     // Skip if the script has been disabled.
     if (!script->canIonCompile())
         return Method_Skipped;
 
     // Skip if the script is being compiled off thread.
     if (script->isIonCompilingOffThread())
         return Method_Skipped;
 
     // Skip if the code is expected to result in a bailout.
     if (script->hasIonScript() && script->ionScript()->bailoutExpected())
         return Method_Skipped;
 
     // If constructing, allocate a new |this| object before building Ion.
     // Creating |this| is done before building Ion because it may change the
     // type information and invalidate compilation results.
-    if (isConstructing && fp.thisValue().isPrimitive()) {
-        RootedObject callee(cx, fp.callee());
-        RootedObject obj(cx, CreateThisForFunction(cx, callee, fp.useNewType()));
-        if (!obj || !ion::IsEnabled(cx)) // Note: OOM under CreateThis can disable TI.
-            return Method_Skipped;
-        fp.thisValue().setObject(*obj);
-    }
-
-    // Mark as forbidden if frame can't be handled.
-    if (!CheckFrame(fp)) {
+    if (state.isInvoke()) {
+        InvokeState &invoke = *state.asInvoke();
+
+        if (TooManyArguments(invoke.args().length())) {
+            IonSpew(IonSpew_Abort, "too many actual args");
+            ForbidCompilation(cx, script);
+            return Method_CantCompile;
+        }
+
+        if (invoke.constructing() && invoke.args().thisv().isPrimitive()) {
+            RootedScript scriptRoot(cx, script);
+            RootedObject callee(cx, &invoke.args().callee());
+            RootedObject obj(cx, CreateThisForFunction(cx, callee, invoke.useNewType()));
+            if (!obj || !ion::IsEnabled(cx)) // Note: OOM under CreateThis can disable TI.
+                return Method_Skipped;
+            invoke.args().setThis(ObjectValue(*obj));
+            script = scriptRoot;
+        }
+    } else if (state.isGenerator()) {
+        IonSpew(IonSpew_Abort, "generator frame");
         ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
     // If --ion-eager is used, compile with Baseline first, so that we
     // can directly enter IonMonkey.
     if (js_IonOptions.eagerCompilation && !script->hasBaselineScript()) {
-        bool newType = isConstructing && fp.asStackFrame()->useNewType();
-        MethodStatus status = CanEnterBaselineJIT(cx, script, fp.asStackFrame(), newType);
+        MethodStatus status = CanEnterBaselineMethod(cx, state);
         if (status != Method_Compiled)
             return status;
     }
 
     // Attempt compilation. Returns Method_Compiled if already compiled.
     RootedScript rscript(cx, script);
-    MethodStatus status = Compile(cx, rscript, fp, NULL, isConstructing, SequentialExecution);
+    bool constructing = state.isInvoke() && state.asInvoke()->constructing();
+    MethodStatus status = Compile(cx, rscript, NULL, NULL, constructing, SequentialExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
     return Method_Compiled;
 }
 
 MethodStatus
-ion::CompileFunctionForBaseline(JSContext *cx, HandleScript script, AbstractFramePtr fp,
+ion::CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
                                 bool isConstructing)
 {
     JS_ASSERT(ion::IsEnabled(cx));
-    JS_ASSERT(fp.fun()->nonLazyScript()->canIonCompile());
-    JS_ASSERT(!fp.fun()->nonLazyScript()->isIonCompilingOffThread());
-    JS_ASSERT(!fp.fun()->nonLazyScript()->hasIonScript());
-    JS_ASSERT(fp.isFunctionFrame());
+    JS_ASSERT(frame->fun()->nonLazyScript()->canIonCompile());
+    JS_ASSERT(!frame->fun()->nonLazyScript()->isIonCompilingOffThread());
+    JS_ASSERT(!frame->fun()->nonLazyScript()->hasIonScript());
+    JS_ASSERT(frame->isFunctionFrame());
 
     // Mark as forbidden if frame can't be handled.
-    if (!CheckFrame(fp)) {
+    if (!CheckFrame(frame)) {
         ForbidCompilation(cx, script);
         return Method_CantCompile;
     }
 
     // Attempt compilation. Returns Method_Compiled if already compiled.
-    MethodStatus status = Compile(cx, script, fp, NULL, isConstructing, SequentialExecution);
+    MethodStatus status = Compile(cx, script, frame, NULL, isConstructing, SequentialExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script);
         return status;
     }
 
     return Method_Compiled;
 }
@@ -1746,18 +1752,17 @@ ion::CanEnterInParallel(JSContext *cx, H
     // condition differently treats it more like an error.
     if (!script->canParallelIonCompile())
         return Method_Skipped;
 
     // Skip if the script is being compiled off thread.
     if (script->isParallelIonCompilingOffThread())
         return Method_Skipped;
 
-    MethodStatus status = Compile(cx, script, AbstractFramePtr(), NULL, false,
-                                  ParallelExecution);
+    MethodStatus status = Compile(cx, script, NULL, NULL, false, ParallelExecution);
     if (status != Method_Compiled) {
         if (status == Method_CantCompile)
             ForbidCompilation(cx, script, ParallelExecution);
         return status;
     }
 
     // This can GC, so afterward, script->parallelIon is
     // not guaranteed to be valid.
@@ -1803,106 +1808,134 @@ ion::CanEnterUsingFastInvoke(JSContext *
 
     if (!script->hasIonScript())
         return Method_Skipped;
 
     return Method_Compiled;
 }
 
 static IonExecStatus
-EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
+EnterIon(JSContext *cx, EnterJitData &data)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Aborted);
     JS_ASSERT(ion::IsEnabled(cx));
-    JS_ASSERT(CheckFrame(fp));
-    JS_ASSERT(!fp->script()->ionScript()->bailoutExpected());
+    JS_ASSERT(!data.osrFrame);
 
     EnterIonCode enter = cx->compartment()->ionCompartment()->enterJIT();
 
-    // maxArgc is the maximum of arguments between the number of actual
-    // arguments and the number of formal arguments. It accounts for |this|.
-    int maxArgc = 0;
-    Value *maxArgv = NULL;
-    unsigned numActualArgs = 0;
-    RootedValue thisv(cx);
-
-    void *calleeToken;
-    if (fp->isFunctionFrame()) {
-        numActualArgs = fp->numActualArgs();
-        maxArgc = Max(numActualArgs, fp->numFormalArgs()) + 1; // +1 = include |this|
-        maxArgv = fp->argv() - 1; // -1 = include |this|
-        calleeToken = CalleeToToken(&fp->callee());
-    } else {
-        calleeToken = CalleeToToken(fp->script());
-        thisv = fp->thisValue();
-        maxArgc = 1;
-        maxArgv = thisv.address();
-    }
-
     // Caller must construct |this| before invoking the Ion function.
-    JS_ASSERT_IF(fp->isConstructing(), fp->functionThis().isObject());
-    RootedValue result(cx, Int32Value(numActualArgs));
+    JS_ASSERT_IF(data.constructing, data.maxArgv[0].isObject());
+
+    data.result.setInt32(data.numActualArgs);
     {
         AssertCompartmentUnchanged pcc(cx);
         IonContext ictx(cx, NULL);
-        JitActivation activation(cx, fp->isConstructing());
+        JitActivation activation(cx, data.constructing);
         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
         AutoFlushInhibitor afi(cx->compartment()->ionCompartment());
 
-        fp->setRunningInJit();
-
-        // Single transition point from Interpreter to Ion.
-        enter(jitcode, maxArgc, maxArgv, fp, calleeToken, /* scopeChain = */ NULL, 0,
-              result.address());
-
-        fp->clearRunningInJit();
+        // Single transition point from Interpreter to Baseline.
+        enter(data.jitcode, data.maxArgc, data.maxArgv, /* osrFrame = */NULL, data.calleeToken,
+              /* scopeChain = */ NULL, 0, data.result.address());
     }
 
-    JS_ASSERT(fp == cx->fp());
     JS_ASSERT(!cx->runtime()->hasIonReturnOverride());
 
-    // The trampoline wrote the return value but did not set the HAS_RVAL flag.
-    fp->setReturnValue(result);
-
-    // Ion callers wrap primitive constructor return.
-    if (!result.isMagic() && fp->isConstructing() && fp->returnValue().isPrimitive())
-        fp->setReturnValue(ObjectValue(fp->constructorThis()));
-
-    JS_ASSERT_IF(result.isMagic(), result.isMagic(JS_ION_ERROR));
-    return result.isMagic() ? IonExec_Error : IonExec_Ok;
+    // Jit callers wrap primitive constructor return.
+    if (!data.result.isMagic() && data.constructing && data.result.isPrimitive())
+        data.result = data.maxArgv[0];
+
+    // Release temporary buffer used for OSR into Ion.
+    cx->runtime()->getIonRuntime(cx)->freeOsrTempData();
+
+    JS_ASSERT_IF(data.result.isMagic(), data.result.isMagic(JS_ION_ERROR));
+    return data.result.isMagic() ? IonExec_Error : IonExec_Ok;
+}
+
+bool
+ion::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals)
+{
+    data.osrFrame = NULL;
+
+    if (state.isInvoke()) {
+        CallArgs &args = state.asInvoke()->args();
+        unsigned numFormals = state.script()->function()->nargs;
+        data.constructing = state.asInvoke()->constructing();
+        data.numActualArgs = args.length();
+        data.maxArgc = Max(args.length(), numFormals) + 1;
+        data.scopeChain = NULL;
+        data.calleeToken = CalleeToToken(args.callee().toFunction());
+
+        if (data.numActualArgs >= numFormals) {
+            data.maxArgv = args.base() + 1;
+        } else {
+            // Pad missing arguments with |undefined|.
+            for (size_t i = 1; i < args.length() + 2; i++) {
+                if (!vals.append(args.base()[i]))
+                    return false;
+            }
+
+            while (vals.length() < numFormals + 1) {
+                if (!vals.append(UndefinedValue()))
+                    return false;
+            }
+
+            JS_ASSERT(vals.length() >= numFormals + 1);
+            data.maxArgv = vals.begin();
+        }
+    } else {
+        data.constructing = false;
+        data.numActualArgs = 0;
+        data.maxArgc = 1;
+        data.maxArgv = state.asExecute()->addressOfThisv();
+        data.scopeChain = state.asExecute()->scopeChain();
+
+        data.calleeToken = CalleeToToken(state.script());
+
+        if (state.script()->isForEval() &&
+            !(state.asExecute()->type() & StackFrame::GLOBAL))
+        {
+            ScriptFrameIter iter(cx);
+            if (iter.isFunctionFrame())
+                data.calleeToken = CalleeToToken(iter.callee());
+        }
+    }
+
+    return true;
 }
 
 IonExecStatus
-ion::Cannon(JSContext *cx, StackFrame *fp)
+ion::Cannon(JSContext *cx, RunState &state)
 {
-    RootedScript script(cx, fp->script());
-    IonScript *ion = script->ionScript();
-    IonCode *code = ion->method();
-    void *jitcode = code->raw();
+    IonScript *ion = state.script()->ionScript();
+
+    EnterJitData data(cx);
+    data.jitcode = ion->method()->raw();
+
+    AutoValueVector vals(cx);
+    if (!SetEnterJitData(cx, data, state, vals))
+        return IonExec_Error;
 
 #if JS_TRACE_LOGGING
     TraceLog(TraceLogging::defaultLogger(),
              TraceLogging::ION_CANNON_START,
              script);
 #endif
 
-    IonExecStatus status = EnterIon(cx, fp, jitcode);
+    IonExecStatus status = EnterIon(cx, data);
 
 #if JS_TRACE_LOGGING
-    if (status == IonExec_Bailout) {
-        TraceLog(TraceLogging::defaultLogger(),
-                 TraceLogging::ION_CANNON_BAIL,
-                 script);
-    } else {
-        TraceLog(TraceLogging::defaultLogger(),
-                 TraceLogging::ION_CANNON_STOP,
-                 script);
-    }
+    TraceLog(TraceLogging::defaultLogger(),
+             TraceLogging::ION_CANNON_STOP,
+             script);
 #endif
 
+    if (status == IonExec_Ok)
+        state.setReturnValue(data.result);
+
     return status;
 }
 
 IonExecStatus
 ion::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args)
 {
     JS_CHECK_RECURSION(cx, return IonExec_Error);
 
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -269,19 +269,19 @@ bool InitializeIon();
 IonContext *GetIonContext();
 IonContext *MaybeGetIonContext();
 
 bool SetIonContext(IonContext *ctx);
 
 bool CanIonCompileScript(JSContext *cx, HandleScript script, bool osr);
 
 MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
-                              AbstractFramePtr fp, jsbytecode *pc, bool isConstructing);
-MethodStatus CanEnter(JSContext *cx, HandleScript script, AbstractFramePtr fp, bool isConstructing);
-MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, AbstractFramePtr fp,
+                              BaselineFrame *frame, jsbytecode *pc, bool isConstructing);
+MethodStatus CanEnter(JSContext *cx, RunState &state);
+MethodStatus CompileFunctionForBaseline(JSContext *cx, HandleScript script, BaselineFrame *frame,
                                         bool isConstructing);
 MethodStatus CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numActualArgs);
 
 MethodStatus CanEnterInParallel(JSContext *cx, HandleScript script);
 
 enum IonExecStatus
 {
     // The method call had to be aborted due to a stack limit check. This
@@ -297,17 +297,21 @@ enum IonExecStatus
 };
 
 static inline bool
 IsErrorStatus(IonExecStatus status)
 {
     return status == IonExec_Error || status == IonExec_Aborted;
 }
 
-IonExecStatus Cannon(JSContext *cx, StackFrame *fp);
+struct EnterJitData;
+
+bool SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals);
+
+IonExecStatus Cannon(JSContext *cx, RunState &state);
 
 // Used to enter Ion from C++ natives like Array.map. Called from FastInvokeGuard.
 IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args);
 
 // Walk the stack and invalidate active Ion frames for the invalid scripts.
 void Invalidate(types::TypeCompartment &types, FreeOp *fop,
                 const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
 void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -29,23 +29,23 @@
 #endif
 
 using namespace js;
 using namespace js::ion;
 
 using mozilla::DebugOnly;
 
 IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
-                       BaselineInspector *inspector, CompileInfo *info, AbstractFramePtr fp,
+                       BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
                        size_t inliningDepth, uint32_t loopDepth)
   : MIRGenerator(cx->compartment(), temp, graph, info),
     backgroundCodegen_(NULL),
     recompileInfo(cx->compartment()->types.compiledInfo),
     cx(cx),
-    fp(fp),
+    baselineFrame_(baselineFrame),
     abortReason_(AbortReason_Disable),
     loopDepth_(loopDepth),
     callerResumePoint_(NULL),
     callerBuilder_(NULL),
     inspector(inspector),
     inliningDepth_(inliningDepth),
     numLoopRestarts_(0),
     failedBoundsCheck_(info->script()->failedBoundsCheck),
@@ -57,17 +57,17 @@ IonBuilder::IonBuilder(JSContext *cx, Te
     script_.init(info->script());
     pc = info->startPC();
 }
 
 void
 IonBuilder::clearForBackEnd()
 {
     cx = NULL;
-    fp = AbstractFramePtr();
+    baselineFrame_ = NULL;
 }
 
 bool
 IonBuilder::abort(const char *message, ...)
 {
     // Don't call PCToLineNumber in release builds.
 #ifdef DEBUG
     va_list ap;
@@ -3455,17 +3455,17 @@ IonBuilder::inlineScriptedCall(CallInfo 
                                                  this->info().executionMode());
     if (!info)
         return false;
 
     MIRGraphExits saveExits;
     AutoAccumulateExits aae(graph(), saveExits);
 
     // Build the graph.
-    IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, AbstractFramePtr(),
+    IonBuilder inlineBuilder(cx, &temp(), &graph(), &inspector, info, NULL,
                              inliningDepth_ + 1, loopDepth_);
     if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) {
         JS_ASSERT(calleeScript->hasAnalysis());
 
         // Inlining the callee failed. Disable inlining the function
         if (inlineBuilder.abortReason_ == AbortReason_Disable)
             calleeScript->analysis()->setIonUninlineable();
 
@@ -5597,29 +5597,29 @@ IonBuilder::newPendingLoopHeader(MBasicB
         // Unbox the MOsrValue if it is known to be unboxable.
         for (uint32_t i = info().startArgSlot(); i < block->stackDepth(); i++) {
             MPhi *phi = block->getSlot(i)->toPhi();
 
             bool haveValue = false;
             Value existingValue;
             if (info().fun() && i == info().thisSlot()) {
                 haveValue = true;
-                existingValue = fp.thisValue();
+                existingValue = baselineFrame_->thisValue();
             } else {
                 uint32_t arg = i - info().firstArgSlot();
                 uint32_t var = i - info().firstLocalSlot();
                 if (arg < info().nargs()) {
                     if (!script()->formalIsAliased(arg)) {
                         haveValue = true;
-                        existingValue = fp.unaliasedFormal(arg);
+                        existingValue = baselineFrame_->unaliasedFormal(arg);
                     }
                 } else if (var < info().nlocals()) {
                     if (!script()->varIsAliased(var)) {
                         haveValue = true;
-                        existingValue = fp.unaliasedVar(var);
+                        existingValue = baselineFrame_->unaliasedVar(var);
                     }
                 }
             }
             if (haveValue) {
                 MIRType type = existingValue.isDouble()
                              ? MIRType_Double
                              : MIRTypeFromValueType(existingValue.extractNonDoubleType());
                 types::Type ntype = types::GetValueType(cx, existingValue);
@@ -8143,17 +8143,17 @@ IonBuilder::jsop_this()
 
     if (script()->strict) {
         current->pushSlot(info().thisSlot());
         return true;
     }
 
     types::StackTypeSet *types = types::TypeScript::ThisTypes(script());
     if (types && (types->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
-                  (types->empty() && fp && fp.thisValue().isObject())))
+                  (types->empty() && baselineFrame_ && baselineFrame_->thisValue().isObject())))
     {
         // This is safe, because if the entry type of |this| is an object, it
         // will necessarily be an object throughout the entire function. OSR
         // can introduce a phi, but this phi will be specialized.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
@@ -8304,18 +8304,18 @@ IonBuilder::hasStaticScopeObject(ScopeCo
         environment = environment->enclosingScope();
     }
 
     // Look for the call object on the current frame, if we are compiling the
     // outer script itself. Don't do this if we are at entry to the outer
     // script, as the call object we see will not be the real one --- after
     // entering the Ion code a different call object will be created.
 
-    if (script() == outerScript && fp && info().osrPc()) {
-        JSObject *scope = fp.scopeChain();
+    if (script() == outerScript && baselineFrame_ && info().osrPc()) {
+        JSObject *scope = baselineFrame_->scopeChain();
         if (scope->is<CallObject>() &&
             scope->as<CallObject>().callee().nonLazyScript() == outerScript)
         {
             JS_ASSERT(scope->hasSingletonType());
             pcall.set(scope);
             return true;
         }
     }
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -193,17 +193,17 @@ class IonBuilder : public MIRGenerator
         static CFGState CondSwitch(jsbytecode *exitpc, jsbytecode *defaultTarget);
         static CFGState Label(jsbytecode *exitpc);
     };
 
     static int CmpSuccessors(const void *a, const void *b);
 
   public:
     IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
-               BaselineInspector *inspector, CompileInfo *info, AbstractFramePtr fp,
+               BaselineInspector *inspector, CompileInfo *info, BaselineFrame *baselineFrame,
                size_t inliningDepth = 0, uint32_t loopDepth = 0);
 
     bool build();
     bool buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
                      CallInfo &callInfo);
 
   private:
     bool traverseBytecode();
@@ -581,17 +581,17 @@ class IonBuilder : public MIRGenerator
 
     CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
     void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
 
     AbortReason abortReason() { return abortReason_; }
 
   private:
     JSContext *cx;
-    AbstractFramePtr fp;
+    BaselineFrame *baselineFrame_;
     AbortReason abortReason_;
 
     jsbytecode *pc;
     MBasicBlock *current;
     uint32_t loopDepth_;
 
     /* Information used for inline-call builders. */
     MResumePoint *callerResumePoint_;
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -931,17 +931,17 @@ GenerateCallGetter(JSContext *cx, IonScr
             Address(StackPointer, IonOOLNativeGetterExitFrameLayout::offsetOfResult()),
             JSReturnOperand);
     } else {
         Register argObjReg       = argUintNReg;
         Register argIdReg        = regSet.takeGeneral();
 
         PropertyOp target = shape->getterOp();
         JS_ASSERT(target);
-        // JSPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+        // JSPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj, JSHandleId id, MutableHandleValue vp)
 
         // Push args on stack first so we can take pointers to make handles.
         masm.Push(UndefinedValue());
         masm.movePtr(StackPointer, argVpReg);
 
         // push canonical jsid from shape instead of propertyname.
         RootedId propId(cx);
         if (!shape->getUserId(cx, &propId))
@@ -1841,17 +1841,17 @@ SetPropertyIC::attachSetterCall(JSContex
 
     Label success, exception;
 
     attacher.pushStubCodePointer(masm);
 
     StrictPropertyOp target = shape->setterOp();
     JS_ASSERT(target);
     // JSStrictPropertyOp: JSBool fn(JSContext *cx, JSHandleObject obj,
-    //                               JSHandleId id, JSBool strict, JSMutableHandleValue vp);
+    //                               JSHandleId id, JSBool strict, MutableHandleValue vp);
 
     // Push args on stack first so we can take pointers to make handles.
     if (value().constant())
         masm.Push(value().value());
     else
         masm.Push(value().reg());
     masm.movePtr(StackPointer, argVpReg);
 
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -21,17 +21,40 @@ namespace ion {
 
 class FrameSizeClass;
 
 enum EnterJitType {
     EnterJitBaseline = 0,
     EnterJitOptimized = 1
 };
 
-typedef void (*EnterIonCode)(void *code, int argc, Value *argv, StackFrame *fp,
+struct EnterJitData
+{
+    explicit EnterJitData(JSContext *cx)
+      : scopeChain(cx),
+        result(cx)
+    {}
+
+    uint8_t *jitcode;
+    StackFrame *osrFrame;
+
+    void *calleeToken;
+
+    Value *maxArgv;
+    unsigned maxArgc;
+    unsigned numActualArgs;
+    unsigned osrNumStackValues;
+
+    RootedObject scopeChain;
+    RootedValue result;
+
+    bool constructing;
+};
+
+typedef void (*EnterIonCode)(void *code, unsigned argc, Value *argv, StackFrame *fp,
                              CalleeToken calleeToken, JSObject *scopeChain,
                              size_t numStackValues, Value *vp);
 
 class IonBuilder;
 
 typedef Vector<IonBuilder*, 0, SystemAllocPolicy> OffThreadCompilationVector;
 
 // ICStubSpace is an abstraction for allocation policy and storage for stub data.
--- a/js/src/ion/MIR.cpp
+++ b/js/src/ion/MIR.cpp
@@ -950,17 +950,17 @@ void
 MUrsh::infer(BaselineInspector *inspector, jsbytecode *pc)
 {
     if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
         specialization_ = MIRType_None;
         setResultType(MIRType_Value);
         return;
     }
 
-    if (inspector->expectedResultType(pc) == MIRType_Double) {
+    if (inspector->hasSeenDoubleResult(pc)) {
         specialization_ = MIRType_Double;
         setResultType(MIRType_Double);
         return;
     }
 
     specialization_ = MIRType_Int32;
     setResultType(MIRType_Int32);
 }
@@ -1304,17 +1304,17 @@ MBinaryArithInstruction::infer(BaselineI
     if (lhs == MIRType_Int32 && rhs == MIRType_Int32)
         setResultType(MIRType_Int32);
     else if (lhs == MIRType_Double || rhs == MIRType_Double)
         setResultType(MIRType_Double);
     else
         return inferFallback(inspector, pc);
 
     // If the operation has ever overflowed, use a double specialization.
-    if (inspector->expectedResultType(pc) == MIRType_Double)
+    if (inspector->hasSeenDoubleResult(pc))
         setResultType(MIRType_Double);
 
     // If the operation will always overflow on its constant operands, use a
     // double specialization so that it can be constant folded later.
     if ((isMul() || isDiv()) && lhs == MIRType_Int32 && rhs == MIRType_Int32) {
         bool typeChange = false;
         EvaluateConstantOperands(this, &typeChange);
         if (typeChange)
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -565,21 +565,16 @@ FilterArguments(JSContext *cx, JSString 
     static const jschar arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
     return !StringHasPattern(chars, str->length(), arguments, mozilla::ArrayLength(arguments));
 }
 
 #ifdef JSGC_GENERATIONAL
 void
 PostWriteBarrier(JSRuntime *rt, JSObject *obj)
 {
-#ifdef JS_GC_ZEAL
-    /* The jitcode version of IsInsideNursery does not know about the verifier. */
-    if (rt->gcVerifyPostData && rt->gcVerifierNursery.isInside(obj))
-        return;
-#endif
     JS_ASSERT(!IsInsideNursery(rt, obj));
     rt->gcStoreBuffer.putWholeCell(obj);
 }
 #endif
 
 uint32_t
 GetIndexFromString(JSString *str)
 {
--- a/js/src/ion/arm/IonFrames-arm.h
+++ b/js/src/ion/arm/IonFrames-arm.h
@@ -345,17 +345,17 @@ class IonOOLPropertyOpExitFrameLayout
     IonExitFrameLayout exit_;
 
     // Object for JSHandleObject
     JSObject *obj_;
 
     // id for JSHandleId
     jsid id_;
 
-    // space for JSMutableHandleValue result
+    // space for MutableHandleValue result
     // use two uint32_t so compiler doesn't align.
     uint32_t vp0_;
     uint32_t vp1_;
 
     // pointer to root the stub's IonCode
     IonCode *stubCode_;
 
   public:
@@ -393,17 +393,17 @@ class IonOOLProxyGetExitFrameLayout
     JSObject *proxy_;
 
     // Object for JSHandleObject
     JSObject *receiver_;
 
     // id for JSHandleId
     jsid id_;
 
-    // space for JSMutableHandleValue result
+    // space for MutableHandleValue result
     // use two uint32_t so compiler doesn't align.
     uint32_t vp0_;
     uint32_t vp1_;
 
     // pointer to root the stub's IonCode
     IonCode *stubCode_;
 
   public:
--- a/js/src/ion/shared/IonFrames-x86-shared.h
+++ b/js/src/ion/shared/IonFrames-x86-shared.h
@@ -309,17 +309,17 @@ class IonOOLPropertyOpExitFrameLayout
     IonExitFrameLayout exit_;
 
     // Object for JSHandleObject
     JSObject *obj_;
 
     // id for JSHandleId
     jsid id_;
 
-    // space for JSMutableHandleValue result
+    // space for MutableHandleValue result
     // use two uint32_t so compiler doesn't align.
     uint32_t vp0_;
     uint32_t vp1_;
 
     // pointer to root the stub's IonCode
     IonCode *stubCode_;
 
   public:
@@ -357,17 +357,17 @@ class IonOOLProxyGetExitFrameLayout
     JSObject *proxy_;
 
     // Object for JSHandleObject
     JSObject *receiver_;
 
     // id for JSHandleId
     jsid id_;
 
-    // space for JSMutableHandleValue result
+    // space for MutableHandleValue result
     // use two uint32_t so compiler doesn't align.
     uint32_t vp0_;
     uint32_t vp1_;
 
     // pointer to root the stub's IonCode
     IonCode *stubCode_;
 
   public:
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/bug877589.js
@@ -0,0 +1,7 @@
+function x() {
+    [1];
+}
+Array.prototype.__proto__ = {};
+x();
+Array.prototype.__proto__ = null;
+x();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug-870034.js
@@ -0,0 +1,12 @@
+// |jit-test| ion-eager
+function f(b) {
+    var a = arguments;
+    if (b)
+        f(false);
+    else
+        g = {
+            apply:function(x,y) { "use asm"; function g() {} return g }
+        };
+    g.apply(null, a);
+}
+f(true);
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -409,22 +409,22 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_GETELEM:
           case JSOP_CALLELEM:
             numPropertyReads_++;
             break;
 
           case JSOP_THROW:
           case JSOP_EXCEPTION:
           case JSOP_DEBUGGER:
-          case JSOP_FUNCALL:
             isIonInlineable = false;
             break;
 
           /* Additional opcodes which can be both compiled both normally and inline. */
           case JSOP_ARGUMENTS:
+          case JSOP_FUNCALL:
           case JSOP_FUNAPPLY:
           case JSOP_CALLEE:
           case JSOP_NOP:
           case JSOP_UNDEFINED:
           case JSOP_GOTO:
           case JSOP_DEFAULT:
           case JSOP_IFEQ:
           case JSOP_IFNE:
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -811,19 +811,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     gcSliceBudget(SliceBudget::Unlimited),
     gcIncrementalEnabled(true),
     gcGenerationalEnabled(true),
     gcManipulatingDeadZones(false),
     gcObjectsMarkedInDeadZones(0),
     gcPoke(false),
     heapState(Idle),
 #ifdef JSGC_GENERATIONAL
-# ifdef JS_GC_ZEAL
-    gcVerifierNursery(),
-# endif
     gcNursery(thisFromCtor()),
     gcStoreBuffer(thisFromCtor()),
 #endif
 #ifdef JS_GC_ZEAL
     gcZeal_(0),
     gcZealFrequency(0),
     gcNextScheduled(0),
     gcDeterministicOnly(false),
@@ -3204,23 +3201,23 @@ JS_DefaultValue(JSContext *cx, JSObject 
     if (!JSObject::defaultValue(cx, obj, hint, &value))
         return false;
 
     *vp = value;
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp)
+JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, MutableHandleValue vp)
 {
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp)
+JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, MutableHandleValue vp)
 {
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded)
 {
     *succeeded = true;
@@ -3235,17 +3232,17 @@ JS_EnumerateStub(JSContext *cx, JSHandle
 
 JS_PUBLIC_API(JSBool)
 JS_ResolveStub(JSContext *cx, JSHandleObject obj, JSHandleId id)
 {
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
-JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp)
+JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, MutableHandleValue vp)
 {
     JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION);
     JS_ASSERT(obj);
     return DefaultValue(cx, obj, type, vp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_InitClass(JSContext *cx, JSObject *objArg, JSObject *parent_protoArg,
@@ -5960,17 +5957,17 @@ JS_PUBLIC_API(void)
 JS_TriggerOperationCallback(JSRuntime *rt)
 {
     rt->triggerOperationCallback();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_IsRunning(JSContext *cx)
 {
-    return cx->hasfp();
+    return cx->currentlyRunning();
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SaveFrameChain(JSContext *cx)
 {
     AssertHeapIsIdleOrIterating(cx);
     CHECK_REQUEST(cx);
     return cx->saveFrameChain();
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -713,39 +713,35 @@ CallNonGenericMethod(JSContext *cx, IsAc
 
 /************************************************************************/
 
 typedef JS::Handle<JSObject*> JSHandleObject;
 typedef JS::Handle<JSString*> JSHandleString;
 typedef JS::Handle<JS::Value> JSHandleValue;
 typedef JS::Handle<jsid> JSHandleId;
 
-typedef JS::MutableHandle<JSFunction*> JSMutableHandleFunction;
-typedef JS::MutableHandle<JSString*>   JSMutableHandleString;
-typedef JS::MutableHandle<JS::Value>   JSMutableHandleValue;
-
 /* JSClass operation signatures. */
 
 /*
  * Add or get a property named by id in obj.  Note the jsid id type -- id may
  * be a string (Unicode property identifier) or an int (element index).  The
  * *vp out parameter, on success, is the new property value after the action.
  */
 typedef JSBool
-(* JSPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+(* JSPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp);
 
 /*
  * Set a property named by id in obj, treating the assignment as strict
  * mode code if strict is true. Note the jsid id type -- id may be a string
  * (Unicode property identifier) or an int (element index). The *vp out
  * parameter, on success, is the new property value after the
  * set.
  */
 typedef JSBool
-(* JSStrictPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp);
+(* JSStrictPropertyOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp);
 
 /*
  * Delete a property named by id in obj.
  *
  * If an error occurred, return false as per normal JSAPI error practice.
  *
  * If no error occurred, but the deletion attempt wasn't allowed (perhaps
  * because the property was non-configurable), set *succeeded to false and
@@ -789,17 +785,17 @@ typedef JSBool
  *    call to this function when enum_op was JSENUMERATE_INIT or
  *    JSENUMERATE_INIT_ALL.
  *
  * The return value is used to indicate success, with a value of JS_FALSE
  * indicating failure.
  */
 typedef JSBool
 (* JSNewEnumerateOp)(JSContext *cx, JSHandleObject obj, JSIterateOp enum_op,
-                     JSMutableHandleValue statep, JS::MutableHandleId idp);
+                     JS::MutableHandle<JS::Value> statep, JS::MutableHandleId idp);
 
 /*
  * The old-style JSClass.enumerate op should define all lazy properties not
  * yet reflected in obj.
  */
 typedef JSBool
 (* JSEnumerateOp)(JSContext *cx, JSHandleObject obj);
 
@@ -834,17 +830,17 @@ typedef JSBool
 (* JSNewResolveOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, unsigned flags,
                    JS::MutableHandleObject objp);
 
 /*
  * Convert obj to the given type, returning true with the resulting value in
  * *vp on success, and returning false on error or exception.
  */
 typedef JSBool
-(* JSConvertOp)(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp);
+(* JSConvertOp)(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp);
 
 typedef struct JSFreeOp JSFreeOp;
 
 struct JSFreeOp {
   private:
     JSRuntime   *runtime_;
 
   protected:
@@ -877,25 +873,25 @@ struct JSStringFinalizer {
 /*
  * JSClass.checkAccess type: check whether obj[id] may be accessed per mode,
  * returning false on error/exception, true on success with obj[id]'s last-got
  * value in *vp, and its attributes in *attrsp.  As for JSPropertyOp above, id
  * is either a string or an int jsval.
  */
 typedef JSBool
 (* JSCheckAccessOp)(JSContext *cx, JSHandleObject obj, JSHandleId id, JSAccessMode mode,
-                    JSMutableHandleValue vp);
+                    JS::MutableHandle<JS::Value> vp);
 
 /*
  * Check whether v is an instance of obj.  Return false on error or exception,
  * true on success with JS_TRUE in *bp if v is an instance of obj, JS_FALSE in
  * *bp otherwise.
  */
 typedef JSBool
-(* JSHasInstanceOp)(JSContext *cx, JSHandleObject obj, JSMutableHandleValue vp, JSBool *bp);
+(* JSHasInstanceOp)(JSContext *cx, JSHandleObject obj, JS::MutableHandle<JS::Value> vp, JSBool *bp);
 
 /*
  * Function type for trace operation of the class called to enumerate all
  * traceable things reachable from obj's private data structure. For each such
  * thing, a trace implementation must call one of the JS_Call*Tracer variants
  * on the thing.
  *
  * JSTraceOp implementation can assume that no other threads mutates object
@@ -1025,27 +1021,27 @@ typedef struct JSErrorFormatString {
     int16_t exnType;
 } JSErrorFormatString;
 
 typedef const JSErrorFormatString *
 (* JSErrorCallback)(void *userRef, const char *locale,
                     const unsigned errorNumber);
 
 typedef JSBool
-(* JSLocaleToUpperCase)(JSContext *cx, JSHandleString src, JSMutableHandleValue rval);
+(* JSLocaleToUpperCase)(JSContext *cx, JSHandleString src, JS::MutableHandle<JS::Value> rval);
 
 typedef JSBool
-(* JSLocaleToLowerCase)(JSContext *cx, JSHandleString src, JSMutableHandleValue rval);
+(* JSLocaleToLowerCase)(JSContext *cx, JSHandleString src, JS::MutableHandle<JS::Value> rval);
 
 typedef JSBool
 (* JSLocaleCompare)(JSContext *cx, JSHandleString src1, JSHandleString src2,
-                    JSMutableHandleValue rval);
+                    JS::MutableHandle<JS::Value> rval);
 
 typedef JSBool
-(* JSLocaleToUnicode)(JSContext *cx, const char *src, JSMutableHandleValue rval);
+(* JSLocaleToUnicode)(JSContext *cx, const char *src, JS::MutableHandle<JS::Value> rval);
 
 /*
  * Security protocol types.
  */
 
 typedef void
 (* JSDestroyPrincipalsOp)(JSPrincipals *principals);
 
@@ -1781,17 +1777,17 @@ IsPoisonedId(jsid iden)
         return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
     return false;
 }
 
 } /* namespace JS */
 
 namespace js {
 
-template <> struct RootMethods<jsid>
+template <> struct GCMethods<jsid>
 {
     static jsid initial() { return JSID_VOID; }
     static ThingRootKind kind() { return THING_ROOT_ID; }
     static bool poisoned(jsid id) { return JS::IsPoisonedId(id); }
     static bool needsPostBarrier(jsid id) { return false; }
 #ifdef JSGC_GENERATIONAL
     static void postBarrier(jsid *idp) {}
     static void relocate(jsid *idp) {}
@@ -2859,17 +2855,17 @@ struct JSClass {
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
  * Implementing this efficiently requires that global objects have classes
  * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  * prevously allowed, but is now an ES5 violation and thus unsupported.
  */
-#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 26)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 25)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
@@ -2962,32 +2958,32 @@ JS_IdToValue(JSContext *cx, jsid id, jsv
  * the specified object, computing a primitive default value for the object.
  * The hint must be JSTYPE_STRING, JSTYPE_NUMBER, or JSTYPE_VOID (no hint).  On
  * success the resulting value is stored in *vp.
  */
 extern JS_PUBLIC_API(JSBool)
 JS_DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp);
 
 extern JS_PUBLIC_API(JSBool)
-JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSMutableHandleValue vp);
+JS_PropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(JSBool)
-JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp);
+JS_StrictPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandle<JS::Value> vp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DeletePropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool *succeeded);
 
 extern JS_PUBLIC_API(JSBool)
 JS_EnumerateStub(JSContext *cx, JSHandleObject obj);
 
 extern JS_PUBLIC_API(JSBool)
 JS_ResolveStub(JSContext *cx, JSHandleObject obj, JSHandleId id);
 
 extern JS_PUBLIC_API(JSBool)
-JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JSMutableHandleValue vp);
+JS_ConvertStub(JSContext *cx, JSHandleObject obj, JSType type, JS::MutableHandle<JS::Value> vp);
 
 struct JSConstDoubleSpec {
     double          dval;
     const char      *name;
     uint8_t         flags;
     uint8_t         spare[3];
 };
 
@@ -3338,17 +3334,17 @@ class PropertyDescriptorOperations
     void setSetterObject(JSObject *obj) { desc()->setter = reinterpret_cast<JSStrictPropertyOp>(obj); }
 };
 
 } /* namespace JS */
 
 namespace js {
 
 template <>
-struct RootMethods<JSPropertyDescriptor> {
+struct GCMethods<JSPropertyDescriptor> {
     static JSPropertyDescriptor initial() { return JSPropertyDescriptor(); }
     static ThingRootKind kind() { return THING_ROOT_PROPERTY_DESCRIPTOR; }
     static bool poisoned(const JSPropertyDescriptor &desc) {
         return (desc.obj && JS::IsPoisonedPtr(desc.obj)) ||
                (desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) ||
                (desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) ||
                (desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing()));
     }
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -166,18 +166,16 @@ js_InitBooleanClass(JSContext *cx, Handl
 
     RootedValue value(cx, ObjectValue(*valueOf));
     if (!JSObject::defineProperty(cx, booleanProto, valueOfName, value,
                                   JS_PropertyStub, JS_StrictPropertyStub, 0))
     {
         return NULL;
     }
 
-    global->setBooleanValueOf(valueOf);
-
     if (!DefineConstructorAndPrototype(cx, global, JSProto_Boolean, ctor, booleanProto))
         return NULL;
 
     return booleanProto;
 }
 
 JSString *
 js_BooleanToString(JSContext *cx, JSBool b)
@@ -190,21 +188,21 @@ js::ToBooleanSlow(const Value &v)
 {
     if (v.isString())
         return v.toString()->length() != 0;
 
     JS_ASSERT(v.isObject());
     return !EmulatesUndefined(&v.toObject());
 }
 
+/*
+ * This slow path is only ever taken for Boolean objects from other
+ * compartments. The only caller of the fast path, JSON's PreprocessValue,
+ * makes sure of that.
+ */
 bool
-js::BooleanGetPrimitiveValueSlow(JSContext *cx, HandleObject obj, Value *vp)
+js::BooleanGetPrimitiveValueSlow(HandleObject wrappedBool, JSContext *cx)
 {
-    InvokeArgsGuard ag;
-    if (!cx->stack.pushInvokeArgs(cx, 0, &ag))
-        return false;
-    ag.setCallee(cx->compartment()->maybeGlobal()->booleanValueOf());
-    ag.setThis(ObjectValue(*obj));
-    if (!Invoke(cx, ag))
-        return false;
-    *vp = ag.rval();
-    return true;
+    JS_ASSERT(wrappedBool->isCrossCompartmentWrapper());
+    JSObject *obj = Wrapper::wrappedObject(wrappedBool);
+    JS_ASSERT(obj);
+    return obj->asBoolean().unbox();
 }
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -16,13 +16,13 @@ extern JSObject *
 js_InitBooleanClass(JSContext *cx, js::HandleObject obj);
 
 extern JSString *
 js_BooleanToString(JSContext *cx, JSBool b);
 
 namespace js {
 
 inline bool
-BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp);
+BooleanGetPrimitiveValue(HandleObject obj, JSContext *cx);
 
 } /* namespace js */
 
 #endif /* jsbool_h___ */
--- a/js/src/jsboolinlines.h
+++ b/js/src/jsboolinlines.h
@@ -11,27 +11,26 @@
 #include "mozilla/Likely.h"
 
 #include "js/RootingAPI.h"
 
 #include "vm/BooleanObject-inl.h"
 
 namespace js {
 
-bool BooleanGetPrimitiveValueSlow(JSContext *, HandleObject, Value *);
+bool
+BooleanGetPrimitiveValueSlow(HandleObject, JSContext *);
 
 inline bool
-BooleanGetPrimitiveValue(JSContext *cx, HandleObject obj, Value *vp)
+BooleanGetPrimitiveValue(HandleObject obj, JSContext *cx)
 {
-    if (obj->isBoolean()) {
-        *vp = BooleanValue(obj->asBoolean().unbox());
-        return true;
-    }
+    if (obj->isBoolean())
+        return obj->asBoolean().unbox();
 
-    return BooleanGetPrimitiveValueSlow(cx, obj, vp);
+    return BooleanGetPrimitiveValueSlow(obj, cx);
 }
 
 inline bool
 EmulatesUndefined(JSObject *obj)
 {
     JSObject *actual = MOZ_LIKELY(!obj->isWrapper()) ? obj : UncheckedUnwrap(obj);
     bool emulatesUndefined = actual->getClass()->emulatesUndefined();
     MOZ_ASSERT_IF(emulatesUndefined, obj->type()->flags & types::OBJECT_FLAG_EMULATES_UNDEFINED);
--- a/js/src/jsclass.h
+++ b/js/src/jsclass.h
@@ -382,17 +382,17 @@ IsObjectWithClass(const Value &v, ESClas
 inline bool
 IsPoisonedSpecialId(js::SpecialId iden)
 {
     if (iden.isObject())
         return IsPoisonedPtr(iden.toObject());
     return false;
 }
 
-template <> struct RootMethods<SpecialId>
+template <> struct GCMethods<SpecialId>
 {
     static SpecialId initial() { return SpecialId(); }
     static ThingRootKind kind() { return THING_ROOT_ID; }
     static bool poisoned(SpecialId id) { return IsPoisonedSpecialId(id); }
 };
 
 }  /* namespace js */
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -343,16 +343,21 @@ js::DestroyContext(JSContext *cx, Destro
     JSRuntime *rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
 
 #ifdef JS_THREADSAFE
     if (cx->outstandingRequests != 0)
         MOZ_CRASH();
 #endif
 
+#if (defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)) && defined(DEBUG)
+    for (int i = 0; i < THING_ROOT_LIMIT; ++i)
+        JS_ASSERT(cx->thingGCRooters[i] == NULL);
+#endif
+
     if (mode != DCM_NEW_FAILED) {
         if (JSContextCallback cxCallback = rt->cxCallback) {
             /*
              * JSCONTEXT_DESTROY callback is not allowed to fail and must
              * return true.
              */
             JS_ALWAYS_TRUE(cxCallback(cx, JSCONTEXT_DESTROY));
         }
@@ -1294,16 +1299,30 @@ JSContext::restoreFrameChain()
 
     if (Activation *act = mainThread().activation())
         act->restoreFrameChain();
 
     if (isExceptionPending())
         wrapPendingException();
 }
 
+bool
+JSContext::currentlyRunning() const
+{
+    for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
+        if (iter.activation()->cx() == this) {
+            if (iter.activation()->hasSavedFrameChain())
+                return false;
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void
 JSRuntime::setGCMaxMallocBytes(size_t value)
 {
     /*
      * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
      * mean that value.
      */
     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -19,17 +19,19 @@
 #include "jsfriendapi.h"
 #include "jsprvtd.h"
 #include "jsatom.h"
 #include "jsclist.h"
 #include "jsgc.h"
 
 #include "ds/LifoAlloc.h"
 #include "frontend/ParseMaps.h"
+#include "gc/Nursery.h"
 #include "gc/Statistics.h"
+#include "gc/StoreBuffer.h"
 #include "js/HashTable.h"
 #include "js/Vector.h"
 #include "vm/DateTime.h"
 #include "vm/SPSProfiler.h"
 #include "vm/Stack.h"
 #include "vm/ThreadPool.h"
 
 #ifdef _MSC_VER
@@ -516,22 +518,16 @@ class PerThreadData : public js::PerThre
     }
     js::AsmJSActivation *asmJSActivationStackFromOwnerThread() const {
         return asmJSActivationStack_;
     }
 
     js::Activation *activation() const {
         return activation_;
     }
-    bool currentlyRunningInInterpreter() const {
-        return activation_->isInterpreter();
-    }
-    bool currentlyRunningInJit() const {
-        return activation_->isJit();
-    }
 
     /*
      * When this flag is non-zero, any attempt to GC will be skipped. It is used
      * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in
      * debugging facilities that cannot tolerate a GC and would rather OOM
      * immediately, such as utilities exposed to GDB. Setting this flag is
      * extremely dangerous and should only be used when in an OOM situation or
      * in non-exposed debugging facilities.
@@ -1040,19 +1036,16 @@ struct JSRuntime : public JS::shadow::Ru
     volatile js::HeapState heapState;
 
     bool isHeapBusy() { return heapState != js::Idle; }
     bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; }
     bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; }
     bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); }
 
 #ifdef JSGC_GENERATIONAL
-# ifdef JS_GC_ZEAL
-    js::gc::VerifierNursery      gcVerifierNursery;
-# endif
     js::Nursery                  gcNursery;
     js::gc::StoreBuffer          gcStoreBuffer;
 #endif
 
     /*
      * These options control the zealousness of the GC. The fundamental values
      * are gcNextScheduled and gcDebugCompartmentGC. At every allocation,
      * gcNextScheduled is decremented. When it reaches zero, we do either a
@@ -1522,17 +1515,17 @@ struct JSContext : js::ContextFriendFiel
     JSRuntime *runtime() const { return runtime_; }
     JSCompartment *compartment() const { return compartment_; }
 
     inline JS::Zone *zone() const {
         JS_ASSERT_IF(!compartment(), !zone_);
         JS_ASSERT_IF(compartment(), js::GetCompartmentZone(compartment()) == zone_);
         return zone_;
     }
-    js::PerThreadData &mainThread() { return runtime()->mainThread; }
+    js::PerThreadData &mainThread() const { return runtime()->mainThread; }
 
   private:
     /* See JSContext::findVersion. */
     JSVersion           defaultVersion;      /* script compilation version */
     JSVersion           versionOverride;     /* supercedes defaultVersion when valid */
     bool                hasVersionOverride;
 
     /* Exception state -- the exception member is a GC root by definition. */
@@ -1612,23 +1605,16 @@ struct JSContext : js::ContextFriendFiel
     js::ContextStack    stack;
 
     /*
      * Current global. This is only safe to use within the scope of the
      * AutoCompartment from which it's called.
      */
     inline js::Handle<js::GlobalObject*> global() const;
 
-    /* ContextStack convenience functions */
-    inline bool hasfp() const               { return stack.hasfp(); }
-    inline js::StackFrame* fp() const       { return stack.fp(); }
-    inline js::StackFrame* maybefp() const  { return stack.maybefp(); }
-    inline js::FrameRegs& regs() const      { return stack.regs(); }
-    inline js::FrameRegs* maybeRegs() const { return stack.maybeRegs(); }
-
     /* Wrap cx->exception for the current compartment. */
     void wrapPendingException();
 
     /* State for object and array toSource conversion. */
     js::ObjectSet       cycleDetectorSet;
 
     /* Per-context optional error reporter. */
     JSErrorReporter     errorReporter;
@@ -1728,16 +1714,32 @@ struct JSContext : js::ContextFriendFiel
     js::Value           iterValue;
 
     bool jitIsBroken;
 
     inline bool typeInferenceEnabled() const;
 
     void updateJITEnabled();
 
+    /* Whether this context has JS frames on the stack. */
+    bool currentlyRunning() const;
+
+    bool currentlyRunningInInterpreter() const {
+        return mainThread().activation()->isInterpreter();
+    }
+    bool currentlyRunningInJit() const {
+        return mainThread().activation()->isJit();
+    }
+    js::StackFrame *interpreterFrame() const {
+        return mainThread().activation()->asInterpreter()->current();
+    }
+    js::FrameRegs &interpreterRegs() const {
+        return mainThread().activation()->asInterpreter()->regs();
+    }
+
 #ifdef MOZ_TRACE_JSCALLS
     /* Function entry/exit debugging callback. */
     JSFunctionCallback    functionCallback;
 
     void doFunctionCallback(const JSFunction *fun,
                             const JSScript *scr,
                             int entering) const
     {
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -121,21 +121,21 @@ NewObjectCache::newObjectFromHit(JSConte
     }
 
     return NULL;
 }
 
 struct PreserveRegsGuard
 {
     PreserveRegsGuard(JSContext *cx, FrameRegs &regs)
-      : prevContextRegs(cx->maybeRegs()), cx(cx), regs_(regs) {
+      : prevContextRegs(cx->stack.maybeRegs()), cx(cx), regs_(regs) {
         cx->stack.repointRegs(&regs_);
     }
     ~PreserveRegsGuard() {
-        JS_ASSERT(cx->maybeRegs() == &regs_);
+        JS_ASSERT(cx->stack.maybeRegs() == &regs_);
         *prevContextRegs = regs_;
         cx->stack.repointRegs(prevContextRegs);
     }
 
     FrameRegs *prevContextRegs;
 
   private:
     JSContext *cx;
@@ -453,17 +453,17 @@ CallSetter(JSContext *cx, HandleObject o
     return CallJSPropertyOpSetter(cx, op, obj, nid, strict, vp);
 }
 
 }  /* namespace js */
 
 inline bool
 JSContext::canSetDefaultVersion() const
 {
-    return !stack.hasfp() && !hasVersionOverride;
+    return !currentlyRunning() && !hasVersionOverride;
 }
 
 inline void
 JSContext::overrideVersion(JSVersion newVersion)
 {
     JS_ASSERT(!canSetDefaultVersion());
     versionOverride = newVersion;
     hasVersionOverride = true;
@@ -513,17 +513,17 @@ JSContext::setDefaultCompartmentObject(J
 
     if (!hasEnteredCompartment()) {
         /*
          * If JSAPI callers want to JS_SetGlobalObject while code is running,
          * they must have entered a compartment (otherwise there will be no
          * final leaveCompartment call to set the context's compartment back to
          * defaultCompartmentObject->compartment()).
          */
-        JS_ASSERT(!hasfp());
+        JS_ASSERT(!currentlyRunning());
         setCompartment(obj ? obj->compartment() : NULL);
         if (throwing)
             wrapPendingException();
     }
 }
 
 inline void
 JSContext::setDefaultCompartmentObjectIfUnset(JSObject *obj)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -71,17 +71,17 @@ IsTopFrameConstructing(JSContext *cx, Ab
     ScriptFrameIter iter(cx);
     JS_ASSERT(iter.abstractFramePtr() == frame);
     return iter.isConstructing();
 }
 
 JSTrapStatus
 js::ScriptDebugPrologue(JSContext *cx, AbstractFramePtr frame)
 {
-    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());
+    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame());
 
     if (!frame.script()->selfHosted) {
         if (frame.isFramePushedByExecute()) {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                 frame.setHookData(hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame),
                                        true, 0, cx->runtime()->debugHooks.executeHookData));
         } else {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.callHook)
@@ -108,17 +108,18 @@ js::ScriptDebugPrologue(JSContext *cx, A
         JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value");
     }
     return status;
 }
 
 bool
 js::ScriptDebugEpilogue(JSContext *cx, AbstractFramePtr frame, bool okArg)
 {
-    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->fp());
+    JS_ASSERT_IF(frame.isStackFrame(), frame.asStackFrame() == cx->interpreterFrame());
+
     JSBool ok = okArg;
 
     // We don't add hook data for self-hosted scripts, so we don't need to check for them, here.
     if (void *hookData = frame.maybeHookData()) {
         if (frame.isFramePushedByExecute()) {
             if (JSInterpreterHook hook = cx->runtime()->debugHooks.executeHook)
                 hook(cx, Jsvalify(frame), IsTopFrameConstructing(cx, frame), false, &ok, hookData);
         } else {
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -399,24 +399,24 @@ JS_FRIEND_API(bool)
 js::IsOriginalScriptFunction(JSFunction *fun)
 {
     return fun->nonLazyScript()->function() == fun;
 }
 
 JS_FRIEND_API(JSScript *)
 js::GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx)
 {
-    if (!cx->hasfp())
+    ScriptFrameIter iter(cx);
+    if (iter.done())
         return NULL;
 
-    StackFrame *fp = cx->fp();
-    if (!fp->isFunctionFrame())
+    if (!iter.isFunctionFrame())
         return NULL;
 
-    RootedFunction scriptedCaller(cx, fp->fun());
+    RootedFunction scriptedCaller(cx, iter.callee());
     RootedScript outermost(cx, scriptedCaller->nonLazyScript());
     for (StaticScopeIter i(cx, scriptedCaller); !i.done(); i++) {
         if (i.type() == StaticScopeIter::FUNCTION)
             outermost = i.funScript();
     }
     return outermost;
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -120,17 +120,17 @@ JS_ObjectToOuterObject(JSContext *cx, JS
 
 extern JS_FRIEND_API(JSObject *)
 JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent);
 
 extern JS_FRIEND_API(JSString *)
 JS_BasicObjectToString(JSContext *cx, JSHandleObject obj);
 
 extern JS_FRIEND_API(JSBool)
-js_GetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp);
+js_GetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JS::MutableHandleValue vp);
 
 JS_FRIEND_API(void)
 js_ReportOverRecursed(JSContext *maybecx);
 
 #ifdef DEBUG
 
 /*
  * Routines to print out values during debugging.  These are FRIEND_API to help
@@ -887,16 +887,22 @@ NukeCrossCompartmentWrappers(JSContext* 
  */
 
 struct ExpandoAndGeneration {
   ExpandoAndGeneration()
     : expando(UndefinedValue()),
       generation(0)
   {}
 
+  void Unlink()
+  {
+      ++generation;
+      expando.setUndefined();
+  }
+
   JS::Heap<JS::Value> expando;
   uint32_t generation;
 };
 
 typedef enum DOMProxyShadowsResult {
   ShadowCheckFailed,
   Shadows,
   DoesntShadow,
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -879,17 +879,17 @@ js_fun_apply(JSContext *cx, unsigned arg
          * function and read actuals out of the frame.
          */
         /* Steps 4-6. */
 
 #ifdef JS_ION
         // We do not want to use ScriptFrameIter to abstract here because this
         // is supposed to be a fast path as opposed to ScriptFrameIter which is
         // doing complex logic to settle on the next frame twice.
-        if (cx->mainThread().currentlyRunningInJit()) {
+        if (cx->currentlyRunningInJit()) {
             ion::JitActivationIterator activations(cx->runtime());
             ion::IonFrameIterator frame(activations);
             if (frame.isNative()) {
                 // Stop on the next Ion JS Frame.
                 ++frame;
                 if (frame.isOptimizedJS()) {
                     ion::InlineFrameIterator iter(cx, &frame);
 
@@ -924,17 +924,17 @@ js_fun_apply(JSContext *cx, unsigned arg
                 JS_ASSERT(frame.isBaselineJS());
 
                 if (!PushBaselineFunApplyArguments(cx, frame, args, vp))