Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 06 Jan 2015 10:52:47 -0500
changeset 248039 4d91c33b351cabf7fb7bff4575e33d92bad45830
parent 247956 089617759278ade26bb298e7cea841e95ae82e69 (current diff)
parent 248038 1f32089c6733f9beeced00dc0aced37f5fe0a585 (diff)
child 248061 b42615e51c8106d2dba57343e34a631190473cb0
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
dom/system/gonk/NetworkUtils.cpp
gfx/layers/composite/ContainerLayerComposite.cpp
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1811,14 +1811,15 @@ pref("browser.tabs.remote.autostart.1", 
 pref("print.enable_e10s_testing", false);
 #else
 pref("print.enable_e10s_testing", true);
 #endif
 
 #ifdef NIGHTLY_BUILD
 // Enable e10s add-on interposition by default.
 pref("extensions.interposition.enabled", true);
+pref("extensions.interposition.prefetching", true);
 #endif
 
 pref("browser.defaultbrowser.notificationbar", false);
 
 // How many milliseconds to wait for a CPOW response from the child process.
 pref("dom.ipc.cpow.timeout", 0);
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -833,16 +833,17 @@ nsDocShell::nsDocShell():
     mAllowContentRetargeting(true),
     mCreatingDocument(false),
     mUseErrorPages(false),
     mObserveErrorPages(true),
     mAllowAuth(true),
     mAllowKeywordFixup(false),
     mIsOffScreenBrowser(false),
     mIsActive(true),
+    mIsPrerendered(false),
     mIsAppTab(false),
     mUseGlobalHistory(false),
     mInPrivateBrowsing(false),
     mUseRemoteTabs(false),
     mDeviceSizeIsPageSize(false),
     mCanExecuteScripts(false),
     mFiredUnloadEvent(false),
     mEODForCurrentDocument(false),
@@ -3381,16 +3382,21 @@ nsDocShell::SetDocLoaderParent(nsDocLoad
             SetAllowWindowControl(value);
         }
         SetAllowContentRetargeting(
             parentAsDocShell->GetAllowContentRetargeting());
         if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value)))
         {
             SetIsActive(value);
         }
+        if (NS_SUCCEEDED(parentAsDocShell->GetIsPrerendered(&value))) {
+            if (value) {
+                SetIsPrerendered(true);
+            }
+        }
         if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
             value = false;
         }
         SetAllowDNSPrefetch(value);
         value = parentAsDocShell->GetAffectPrivateSessionLifetime();
         SetAffectPrivateSessionLifetime(value);
         uint32_t flags;
         if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags)))
@@ -6048,16 +6054,32 @@ nsDocShell::SetIsActive(bool aIsActive)
 NS_IMETHODIMP
 nsDocShell::GetIsActive(bool *aIsActive)
 {
     *aIsActive = mIsActive;
     return NS_OK;
 }
 
 NS_IMETHODIMP
+nsDocShell::SetIsPrerendered(bool aPrerendered)
+{
+    MOZ_ASSERT(!aPrerendered || !mIsPrerendered,
+               "SetIsPrerendered(true) called on already prerendered docshell");
+    mIsPrerendered = aPrerendered;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocShell::GetIsPrerendered(bool *aIsPrerendered)
+{
+    *aIsPrerendered = mIsPrerendered;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDocShell::SetIsAppTab(bool aIsAppTab)
 {
     mIsAppTab = aIsAppTab;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsAppTab(bool *aIsAppTab)
@@ -8548,18 +8570,18 @@ nsDocShell::RestoreFromHistory()
 
         bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
 
         uint32_t defaultLoadFlags;
         childShell->GetDefaultLoadFlags(&defaultLoadFlags);
 
         // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning
         // that the child inherits our state. Among other things, this means
-        // that the child inherits our mIsActive and mInPrivateBrowsing, which
-        // is what we want.
+        // that the child inherits our mIsActive, mIsPrerendered and mInPrivateBrowsing,
+        // which is what we want.
         AddChild(childItem);
 
         childShell->SetAllowPlugins(allowPlugins);
         childShell->SetAllowJavascript(allowJavascript);
         childShell->SetAllowMetaRedirects(allowRedirects);
         childShell->SetAllowSubframes(allowSubframes);
         childShell->SetAllowImages(allowImages);
         childShell->SetAllowMedia(allowMedia);
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -872,16 +872,17 @@ protected:
     bool                       mAllowContentRetargeting;
     bool                       mCreatingDocument; // (should be) debugging only
     bool                       mUseErrorPages;
     bool                       mObserveErrorPages;
     bool                       mAllowAuth;
     bool                       mAllowKeywordFixup;
     bool                       mIsOffScreenBrowser;
     bool                       mIsActive;
+    bool                       mIsPrerendered;
     bool                       mIsAppTab;
     bool                       mUseGlobalHistory;
     bool                       mInPrivateBrowsing;
     bool                       mUseRemoteTabs;
     bool                       mDeviceSizeIsPageSize;
 
     // Because scriptability depends on the mAllowJavascript values of our
     // ancestors, we cache the effective scriptability and recompute it when
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -49,17 +49,17 @@ interface nsIWebBrowserPrint;
 interface nsIVariant;
 interface nsIPrivacyTransitionObserver;
 interface nsIReflowObserver;
 interface nsIScrollObserver;
 interface nsITabParent;
  
 typedef unsigned long nsLoadFlags;
 
-[scriptable, builtinclass, uuid(c2756385-bc54-417b-9ae4-c5a40053a2a3)]
+[scriptable, builtinclass, uuid(fef3bae1-6673-4c49-9f5a-fcc075926730)]
 interface nsIDocShell : nsIDocShellTreeItem
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -615,16 +615,23 @@ interface nsIDocShell : nsIDocShellTreeI
   /**
    * Sets whether a docshell is active. An active docshell is one that is
    * visible, and thus is not a good candidate for certain optimizations
    * like image frame discarding. Docshells are active unless told otherwise.
    */
   attribute boolean isActive;
 
   /**
+   * Puts the docshell in prerendering mode. noscript because we want only
+   * native code to be able to put a docshell in prerendering.
+   */
+  [noscript] void SetIsPrerendered(in boolean prerendered);
+  readonly attribute boolean isPrerendered;
+
+  /**
    * The ID of the docshell in the session history.
    */
   readonly attribute unsigned long long historyID;
 
   /**
    * Sets whether a docshell is an app tab. An app tab docshell may behave
    * differently than a non-app tab docshell in some cases, such as when
    * handling link clicks. Docshells are not app tabs unless told otherwise.
--- a/dom/animation/AnimationTimeline.cpp
+++ b/dom/animation/AnimationTimeline.cpp
@@ -55,24 +55,18 @@ AnimationTimeline::FastForward(const Tim
   // nsDOMWindowUtils::AdvanceTimeAndRefresh automatically starts any
   // pending animation players so we don't need to fast-forward the timeline
   // anyway.
   nsRefreshDriver* refreshDriver = GetRefreshDriver();
   if (refreshDriver && refreshDriver->IsTestControllingRefreshesEnabled()) {
     return;
   }
 
-  // Bug 1113413: If the refresh driver has just been restored from test
-  // control it's possible that aTimeStamp could be before the most recent
-  // refresh.
-  if (refreshDriver &&
-      aTimeStamp < refreshDriver->MostRecentRefresh()) {
-    mFastForwardTime = refreshDriver->MostRecentRefresh();
-    return;
-  }
+  MOZ_ASSERT(!refreshDriver || aTimeStamp >= refreshDriver->MostRecentRefresh(),
+             "aTimeStamp must be >= the refresh driver time");
 
   // FIXME: For all animations attached to this timeline, we should mark
   // their target elements as needing restyling. Otherwise, tasks that run
   // in between now and the next refresh driver tick might see inconsistencies
   // between the timing of an animation and the computed style of its target.
 
   mFastForwardTime = aTimeStamp;
 }
--- a/dom/animation/test/css-transitions/test_animation-player-ready.html
+++ b/dom/animation/test/css-transitions/test_animation-player-ready.html
@@ -62,9 +62,41 @@ async_test(function(t) {
 
   // Now remove transform from transition-property and flush styles
   div.style.transitionProperty = 'none';
   window.getComputedStyle(div).transitionProperty;
 
 }, 'ready promise is rejected when a transition is cancelled by updating'
    + ' transition-property');
 
+async_test(function(t) {
+  var div = addDiv(t);
+
+  // Set up pending transition
+  div.style.marginLeft = '0px';
+  window.getComputedStyle(div).marginLeft;
+  div.style.transition = 'margin-left 100s';
+  div.style.marginLeft = '100px';
+  window.getComputedStyle(div).marginLeft;
+
+  var player = div.getAnimationPlayers()[0];
+  assert_equals(player.playState, 'pending', 'Player is initially pending');
+
+  // Set up listeners on ready promise
+  player.ready.then(t.step_func(function() {
+    assert_unreached('ready promise was fulfilled');
+  })).catch(t.step_func(function(err) {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+    assert_equals(player.playState, 'idle',
+                  'Player is idle after transition was cancelled');
+  })).then(t.step_func(function() {
+    t.done();
+  }));
+
+  // Now update the transition to animate to something not-interpolable
+  div.style.marginLeft = 'auto';
+  window.getComputedStyle(div).marginLeft;
+
+}, 'ready promise is rejected when a transition is cancelled by changing'
+   + ' the transition property to something not interpolable');
+
 </script>
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -2,17 +2,17 @@
 support-files =
   testcommon.js
 
 [animation-timeline/test_animation-timeline.html]
 skip-if = buildapp == 'mulet'
 [css-animations/test_animations-dynamic-changes.html]
 [css-animations/test_animation-effect-name.html]
 [css-animations/test_animation-pausing.html]
-skip-if = os == "mac" && os_version == "10.8" # disabled until bug 1112480 lands
+skip-if = os == "win" || (os == "mac" && os_version == "10.8") # disabled until bug 1112480 lands
 [css-animations/test_animation-player-playstate.html]
 [css-animations/test_animation-player-ready.html]
 [css-animations/test_animation-target.html]
 [css-animations/test_element-get-animation-players.html]
 skip-if = buildapp == 'mulet'
 [css-transitions/test_animation-effect-name.html]
 [css-transitions/test_animation-pausing.html]
 [css-transitions/test_animation-player-ready.html]
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -402,17 +402,23 @@ this.PermissionsTable =  { geolocation: 
                              certified: ALLOW_ACTION
                            },
                            "audio-capture": {
                              app: PROMPT_ACTION,
                              trusted: PROMPT_ACTION,
                              privileged: PROMPT_ACTION,
                              certified: ALLOW_ACTION
                            },
-                           "nfc": {
+                           "audio-capture:3gpp": {
+			     app: DENY_ACTION,
+			     trusted: DENY_ACTION,
+			     privileged: ALLOW_ACTION,
+			     certified: ALLOW_ACTION
+			   },
+			   "nfc": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "nfc-share": {
                              app: DENY_ACTION,
                              trusted: DENY_ACTION,
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -196,21 +196,17 @@ EventSource::Init(nsISupports* aOwner,
   nsCOMPtr<nsIPrincipal> principal = scriptPrincipal->GetPrincipal();
   NS_ENSURE_STATE(principal);
 
   mPrincipal = principal;
   mWithCredentials = aWithCredentials;
 
   // The conditional here is historical and not necessarily sane.
   if (JSContext *cx = nsContentUtils::GetCurrentJSContext()) {
-    const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mScriptLine)) {
-      mScriptFile.AssignASCII(filename);
-    }
-
+    nsJSUtils::GetCallingLocation(cx, mScriptFile, &mScriptLine);
     mInnerWindowID = nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx);
   }
 
   // Get the load group for the page. When requesting we'll add ourselves to it.
   // This way any pending requests will be automatically aborted if the user
   // leaves the page.
   nsresult rv;
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -78,27 +78,31 @@ WindowNamedPropertiesHandler::getOwnProp
                                                    JS::MutableHandle<JSPropertyDescriptor> aDesc)
                                                    const
 {
   if (!JSID_IS_STRING(aId)) {
     // Nothing to do if we're resolving a non-string property.
     return true;
   }
 
-  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
-  if (HasPropertyOnPrototype(aCx, aProxy, aId)) {
+  bool hasOnPrototype;
+  if (!HasPropertyOnPrototype(aCx, aProxy, aId, &hasOnPrototype)) {
+    return false;
+  }
+  if (hasOnPrototype) {
     return true;
   }
 
   nsAutoJSString str;
   if (!str.init(aCx, JSID_TO_STRING(aId))) {
     return false;
   }
 
   // Grab the DOM window.
+  JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, aProxy));
   nsGlobalWindow* win = xpc::WindowOrNull(global);
   if (win->Length() > 0) {
     nsCOMPtr<nsIDOMWindow> childWin = win->GetChildWindow(str);
     if (childWin && ShouldExposeChildWindow(str, childWin)) {
       // We found a subframe of the right name. Shadowing via |var foo| in
       // global scope is still allowed, since |var| only looks up |own|
       // properties. But unqualified shadowing will fail, per-spec.
       JS::Rooted<JS::Value> v(aCx);
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -3359,22 +3359,17 @@ nsContentUtils::ReportToConsoleNonLocali
     rv = CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsAutoCString spec;
   if (!aLineNumber) {
     JSContext *cx = GetCurrentJSContext();
     if (cx) {
-      const char* filename;
-      uint32_t lineno;
-      if (nsJSUtils::GetCallingLocation(cx, &filename, &lineno)) {
-        spec = filename;
-        aLineNumber = lineno;
-      }
+      nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber);
     }
   }
   if (spec.IsEmpty() && aURI)
     aURI->GetSpec(spec);
 
   nsCOMPtr<nsIScriptError> errorObject =
       do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsElementFrameLoaderOwner.cpp
+++ b/dom/base/nsElementFrameLoaderOwner.cpp
@@ -107,16 +107,19 @@ nsElementFrameLoaderOwner::EnsureFrameLo
       mFrameLoaderCreationDisallowed) {
     // If frame loader is there, we just keep it around, cached
     return;
   }
 
   // Strangely enough, this method doesn't actually ensure that the
   // frameloader exists.  It's more of a best-effort kind of thing.
   mFrameLoader = nsFrameLoader::Create(thisElement, mNetworkCreated);
+  if (mIsPrerendered) {
+    mFrameLoader->SetIsPrerendered();
+  }
 }
 
 NS_IMETHODIMP
 nsElementFrameLoaderOwner::GetFrameLoader(nsIFrameLoader **aFrameLoader)
 {
   NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
   return NS_OK;
 }
@@ -130,16 +133,24 @@ nsElementFrameLoaderOwner::GetFrameLoade
 
 NS_IMETHODIMP
 nsElementFrameLoaderOwner::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
 {
   // We don't support this yet
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+NS_IMETHODIMP
+nsElementFrameLoaderOwner::SetIsPrerendered()
+{
+  MOZ_ASSERT(!mFrameLoader, "Please call SetIsPrerendered before frameLoader is created");
+  mIsPrerendered = true;
+  return NS_OK;
+}
+
 nsresult
 nsElementFrameLoaderOwner::LoadSrc()
 {
   EnsureFrameLoader();
 
   if (!mFrameLoader) {
     return NS_OK;
   }
--- a/dom/base/nsElementFrameLoaderOwner.h
+++ b/dom/base/nsElementFrameLoaderOwner.h
@@ -28,16 +28,17 @@ class nsXULElement;
 /**
  * A helper class for frame elements
  */
 class nsElementFrameLoaderOwner : public nsIFrameLoaderOwner
 {
 public:
   explicit nsElementFrameLoaderOwner(mozilla::dom::FromParser aFromParser)
     : mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
+    , mIsPrerendered(false)
     , mBrowserFrameListenersRegistered(false)
     , mFrameLoaderCreationDisallowed(false)
   {
   }
 
   virtual ~nsElementFrameLoaderOwner();
 
   NS_DECL_NSIFRAMELOADEROWNER
@@ -65,13 +66,14 @@ protected:
 
   /**
    * True when the element is created by the parser using the
    * NS_FROM_PARSER_NETWORK flag.
    * If the element is modified, it may lose the flag.
    */
   bool mNetworkCreated;
 
+  bool mIsPrerendered;
   bool mBrowserFrameListenersRegistered;
   bool mFrameLoaderCreationDisallowed;
 };
 
 #endif // nsElementFrameLoaderOwner_h
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -149,16 +149,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIFrameLoader)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFrameLoader)
 NS_INTERFACE_MAP_END
 
 nsFrameLoader::nsFrameLoader(Element* aOwner, bool aNetworkCreated)
   : mOwnerContent(aOwner)
   , mAppIdSentToPermissionManager(nsIScriptSecurityManager::NO_APP_ID)
   , mDetachedSubdocViews(nullptr)
+  , mIsPrerendered(false)
   , mDepthTooGreat(false)
   , mIsTopLevelContent(false)
   , mDestroyCalled(false)
   , mNeedsAsyncDestroy(false)
   , mInSwap(false)
   , mInShow(false)
   , mHideCalled(false)
   , mNetworkCreated(aNetworkCreated)
@@ -290,16 +291,25 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
   mURIToLoad = aURI;
   rv = doc->InitializeFrameLoader(this);
   if (NS_FAILED(rv)) {
     mURIToLoad = nullptr;
   }
   return rv;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::SetIsPrerendered()
+{
+  MOZ_ASSERT(!mDocShell, "Please call SetIsPrerendered before docShell is created");
+  mIsPrerendered = true;
+
+  return NS_OK;
+}
+
 nsresult
 nsFrameLoader::ReallyStartLoading()
 {
   nsresult rv = ReallyStartLoadingInternal();
   if (NS_FAILED(rv)) {
     FireErrorEvent();
   }
   
@@ -1608,16 +1618,21 @@ nsFrameLoader::MaybeCreateDocShell()
   nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
   nsCOMPtr<nsIWebNavigation> parentAsWebNav = do_QueryInterface(docShell);
   NS_ENSURE_STATE(parentAsWebNav);
 
   // Create the docshell...
   mDocShell = do_CreateInstance("@mozilla.org/docshell;1");
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
+  if (mIsPrerendered) {
+    nsresult rv = mDocShell->SetIsPrerendered(true);
+    NS_ENSURE_SUCCESS(rv,rv);
+  }
+
   // Apply sandbox flags even if our owner is not an iframe, as this copies
   // flags from our owning content's owning document.
   uint32_t sandboxFlags = 0;
   if (!mOwnerContent->IsSVG(nsGkAtoms::iframe)) {
     HTMLIFrameElement* iframe = HTMLIFrameElement::FromContent(mOwnerContent);
     if (iframe) {
       sandboxFlags = iframe->GetSandboxFlags();
     }
--- a/dom/base/nsFrameLoader.h
+++ b/dom/base/nsFrameLoader.h
@@ -326,16 +326,17 @@ private:
   nsView* mDetachedSubdocViews;
   // Stores the containing document of the frame corresponding to this
   // frame loader. This is reference is kept valid while the subframe's
   // presentation is detached and stored in mDetachedSubdocViews. This
   // enables us to detect whether the frame has moved documents during
   // a reframe, so that we know not to restore the presentation.
   nsCOMPtr<nsIDocument> mContainerDocWhileDetached;
 
+  bool mIsPrerendered : 1;
   bool mDepthTooGreat : 1;
   bool mIsTopLevelContent : 1;
   bool mDestroyCalled : 1;
   bool mNeedsAsyncDestroy : 1;
   bool mInSwap : 1;
   bool mInShow : 1;
   bool mHideCalled : 1;
   // True when the object is created for an element which the parser has
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -946,16 +946,17 @@ GK_ATOM(popupsinherittooltip, "popupsinh
 GK_ATOM(position, "position")
 GK_ATOM(poster, "poster")
 GK_ATOM(pre, "pre")
 GK_ATOM(preceding, "preceding")
 GK_ATOM(precedingSibling, "preceding-sibling")
 GK_ATOM(predicate, "predicate")
 GK_ATOM(prefix, "prefix")
 GK_ATOM(preload, "preload")
+GK_ATOM(prerendered, "prerendered")
 GK_ATOM(preserve, "preserve")
 GK_ATOM(preserveSpace, "preserve-space")
 GK_ATOM(preventdefault, "preventdefault")
 GK_ATOM(primary, "primary")
 GK_ATOM(print, "print")
 GK_ATOM(priority, "priority")
 GK_ATOM(processingInstruction, "processing-instruction")
 GK_ATOM(profile, "profile")
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1113,16 +1113,18 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
     mNetworkDownloadObserverEnabled(false),
 #endif
     mCleanedUp(false),
     mDialogAbuseCount(0),
     mAreDialogsEnabled(true),
     mCanSkipCCGeneration(0),
     mVRDevicesInitialized(false)
 {
+  AssertIsOnMainThread();
+
   nsLayoutStatics::AddRef();
 
   // Initialize the PRCList (this).
   PR_INIT_CLIST(this);
 
   if (aOuterWindow) {
     // |this| is an inner window, add this inner window to the outer
     // window list of inners.
@@ -1213,20 +1215,33 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalW
 
   // Ensure that the current active state is initialized for child process windows.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     mIsActive = fm->IsParentActivated();
   }
 }
 
+#ifdef DEBUG
+
+/* static */
+void
+nsGlobalWindow::AssertIsOnMainThread()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+#endif // DEBUG
+
 /* static */
 void
 nsGlobalWindow::Init()
 {
+  AssertIsOnMainThread();
+
   CallGetService(NS_ENTROPYCOLLECTOR_CONTRACTID, &gEntropyCollector);
   NS_ASSERTION(gEntropyCollector,
                "gEntropyCollector should have been initialized!");
 
 #ifdef PR_LOGGING
   gDOMLeakPRLog = PR_NewLogModule("DOMLeak");
   NS_ASSERTION(gDOMLeakPRLog, "gDOMLeakPRLog should have been initialized!");
 #endif
@@ -1240,16 +1255,18 @@ DisconnectEventTargetObjects(nsPtrHashKe
 {
   nsRefPtr<DOMEventTargetHelper> target = aKey->GetKey();
   target->DisconnectFromOwner();
   return PL_DHASH_NEXT;
 }
 
 nsGlobalWindow::~nsGlobalWindow()
 {
+  AssertIsOnMainThread();
+
   mEventTargetObjects.EnumerateEntries(DisconnectEventTargetObjects, nullptr);
   mEventTargetObjects.Clear();
 
   // We have to check if sWindowsById isn't null because ::Shutdown might have
   // been called.
   if (sWindowsById) {
     NS_ASSERTION(sWindowsById->Get(mWindowID),
                  "This window should be in the hash table");
@@ -1358,16 +1375,18 @@ nsGlobalWindow::RemoveEventTargetObject(
   MOZ_ASSERT(IsInnerWindow());
   mEventTargetObjects.RemoveEntry(aObject);
 }
 
 // static
 void
 nsGlobalWindow::ShutDown()
 {
+  AssertIsOnMainThread();
+
   if (gDumpFile && gDumpFile != stdout) {
     fclose(gDumpFile);
   }
   gDumpFile = nullptr;
 
   NS_IF_RELEASE(gEntropyCollector);
 
   delete sWindowsById;
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -329,16 +329,24 @@ class nsGlobalWindow : public mozilla::d
                        public nsIInterfaceRequestor,
                        public PRCListStr
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;
 
+  static void
+  AssertIsOnMainThread()
+#ifdef DEBUG
+  ;
+#else
+  { }
+#endif
+
   // public methods
   nsPIDOMWindow* GetPrivateParent();
 
   // callback for close event
   void ReallyCloseWindow();
 
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@@ -665,34 +673,40 @@ public:
                         const nsAString& aPopupWindowName,
                         const nsAString& aPopupWindowFeatures) MOZ_OVERRIDE;
 
   virtual uint32_t GetSerial() {
     return mSerial;
   }
 
   static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
     return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nullptr;
   }
 
   static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID) {
+    AssertIsOnMainThread();
+
     if (!sWindowsById) {
       return nullptr;
     }
 
     nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
     return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
   }
 
   static WindowByIdTable* GetWindowsTable() {
+    AssertIsOnMainThread();
+
     return sWindowsById;
   }
 
   void AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;
 
   void UnmarkGrayTimers();
 
   // Inner windows only.
--- a/dom/base/nsIFrameLoader.idl
+++ b/dom/base/nsIFrameLoader.idl
@@ -11,17 +11,17 @@ interface nsIURI;
 interface nsIFrame;
 interface nsSubDocumentFrame;
 interface nsIMessageSender;
 interface nsIVariant;
 interface nsIDOMElement;
 interface nsITabParent;
 interface nsILoadContext;
 
-[scriptable, builtinclass, uuid(7600aa92-88dc-491c-896d-0564159b6a66)]
+[scriptable, builtinclass, uuid(28b6b043-46ec-412f-9be9-db22938b0d6d)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -45,16 +45,21 @@ interface nsIFrameLoader : nsISupports
 
   /**
    * Loads the specified URI in this frame. Behaves identically to loadFrame,
    * except that this method allows specifying the URI to load.
    */
   void loadURI(in nsIURI aURI);
 
   /**
+   * Puts the frameloader in prerendering mode.
+   */
+  void setIsPrerendered();
+
+  /**
    * Destroy the frame loader and everything inside it. This will
    * clear the weak owner content reference.
    */
   void destroy();
 
   /**
    * Find out whether the loader's frame is at too great a depth in
    * the frame tree.  This can be used to decide what operations may
@@ -187,26 +192,31 @@ interface nsIFrameLoader : nsISupports
 };
 
 %{C++
 class nsFrameLoader;
 %}
 
 native alreadyAddRefed_nsFrameLoader(already_AddRefed<nsFrameLoader>);
 
-[scriptable, uuid(5879040e-83e9-40e3-b2bb-5ddf43b76e47)]
+[scriptable, uuid(c4abebcf-55f3-47d4-af15-151311971255)]
 interface nsIFrameLoaderOwner : nsISupports
 {
   /**
    * The frame loader owned by this nsIFrameLoaderOwner
    */
   readonly attribute nsIFrameLoader frameLoader;
   [noscript, notxpcom] alreadyAddRefed_nsFrameLoader GetFrameLoader();
 
   /**
+   * Puts the FrameLoaderOwner in prerendering mode.
+   */
+  void setIsPrerendered();
+
+  /**
    * Swap frame loaders with the given nsIFrameLoaderOwner.  This may
    * only be posible in a very limited range of circumstances, or
    * never, depending on the object implementing this interface.
    *
    * @throws NS_ERROR_NOT_IMPLEMENTED if the swapping logic is not
    *   implemented for the two given frame loader owners.
    * @throws NS_ERROR_DOM_SECURITY_ERR if the swap is not allowed on
    *   security grounds.
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -168,21 +168,18 @@ CheckCSPForEval(JSContext* aCx, nsGlobal
 
   if (reportViolation) {
     // TODO : need actual script sample in violation report.
     NS_NAMED_LITERAL_STRING(scriptSample,
                             "call to eval() or related function blocked by CSP");
 
     // Get the calling location.
     uint32_t lineNum = 0;
-    const char *fileName;
     nsAutoString fileNameString;
-    if (nsJSUtils::GetCallingLocation(aCx, &fileName, &lineNum)) {
-      AppendUTF8toUTF16(fileName, fileNameString);
-    } else {
+    if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
       fileNameString.AssignLiteral("unknown");
     }
 
     csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
                              fileNameString, scriptSample, lineNum,
                              EmptyString(), EmptyString());
   }
 
@@ -228,20 +225,17 @@ nsJSScriptTimeoutHandler::nsJSScriptTime
   }
 
   *aAllowEval = CheckCSPForEval(aCx, aWindow, aError);
   if (aError.Failed() || !*aAllowEval) {
     return;
   }
 
   // Get the calling location.
-  const char *filename;
-  if (nsJSUtils::GetCallingLocation(aCx, &filename, &mLineNo)) {
-    mFileName.Assign(filename);
-  }
+  nsJSUtils::GetCallingLocation(aCx, mFileName, &mLineNo);
 }
 
 nsJSScriptTimeoutHandler::~nsJSScriptTimeoutHandler()
 {
   ReleaseJSObjects();
 }
 
 void
@@ -348,20 +342,17 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
     if (error.Failed() || !*aAllowEval) {
       return error.ErrorCode();
     }
 
     MOZ_ASSERT(mExpr.IsEmpty());
     AssignJSFlatString(mExpr, expr);
 
     // Get the calling location.
-    const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
-      mFileName.Assign(filename);
-    }
+    nsJSUtils::GetCallingLocation(cx, mFileName, &mLineNo);
   } else if (funobj) {
     *aAllowEval = true;
 
     mozilla::HoldJSObjects(this);
 
     mFunction = new Function(funobj, GetIncumbentGlobal());
 
     // Create our arg array.  argc is the number of arguments passed
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -29,29 +29,38 @@
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ScriptSettings.h"
 
 using namespace mozilla::dom;
 
 bool
-nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
+nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
                               uint32_t* aLineno)
 {
   JS::AutoFilename filename;
-  unsigned lineno = 0;
-
-  if (!JS::DescribeScriptedCaller(aContext, &filename, &lineno)) {
+  if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
     return false;
   }
 
-  *aFilename = filename.get();
-  *aLineno = lineno;
+  aFilename.Assign(filename.get());
+  return true;
+}
 
+bool
+nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
+                              uint32_t* aLineno)
+{
+  JS::AutoFilename filename;
+  if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno)) {
+    return false;
+  }
+
+  aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()));
   return true;
 }
 
 nsIScriptGlobalObject *
 nsJSUtils::GetStaticScriptGlobal(JSObject* aObj)
 {
   if (!aObj)
     return nullptr;
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -27,17 +27,19 @@ namespace dom {
 class AutoJSAPI;
 class Element;
 }
 }
 
 class nsJSUtils
 {
 public:
-  static bool GetCallingLocation(JSContext* aContext, const char* *aFilename,
+  static bool GetCallingLocation(JSContext* aContext, nsACString& aFilename,
+                                 uint32_t* aLineno);
+  static bool GetCallingLocation(JSContext* aContext, nsAString& aFilename,
                                  uint32_t* aLineno);
 
   static nsIScriptGlobalObject *GetStaticScriptGlobal(JSObject* aObj);
 
   static nsIScriptContext *GetStaticScriptContext(JSObject* aObj);
 
   /**
    * Retrieve the inner window ID based on the given JSContext.
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -319,16 +319,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
                   "Can't insert document or attribute nodes into a parent");
 
   *aResult = nullptr;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is true, deal with aNode's children (and recurse into their
   // attributes and children).
 
+  nsAutoScriptBlocker scriptBlocker;
   AutoJSContext cx;
   nsresult rv;
 
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   NodeInfo *nodeInfo = aNode->mNodeInfo;
   nsRefPtr<NodeInfo> newNodeInfo;
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -1195,16 +1195,22 @@ nsObjectLoadingContent::GetFrameLoader(n
 NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
 nsObjectLoadingContent::GetFrameLoader()
 {
   nsRefPtr<nsFrameLoader> loader = mFrameLoader;
   return loader.forget();
 }
 
 NS_IMETHODIMP
+nsObjectLoadingContent::SetIsPrerendered()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
 nsObjectLoadingContent::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherLoader)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetActualType(nsACString& aType)
 {
--- a/dom/base/test/TestCSPParser.cpp
+++ b/dom/base/test/TestCSPParser.cpp
@@ -361,16 +361,20 @@ nsresult TestPaths() {
     { "report-uri /examplepath",
       "report-uri http://www.selfuri.com/examplepath" },
     { "connect-src http://www.example.com/foo%3Bsessionid=12%2C34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://www.example.com/foo%3bsessionid=12%2c34",
       "connect-src http://www.example.com/foo;sessionid=12,34" },
     { "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@",
       "connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" },
+    { "script-src http://www.example.com:88/.js",
+      "script-src http://www.example.com:88/.js" },
+    { "script-src https://foo.com/_abc/abc_/_/_a_b_c_",
+      "script-src https://foo.com/_abc/abc_/_/_a_b_c_" }
   };
 
   uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest);
   return runTestSuite(policies, policyCount, 1);
 }
 
 // ============================= TestSimplePolicies ========================
 
@@ -485,18 +489,16 @@ nsresult TestPoliciesWithInvalidSrc() {
     { "script-src http://www.example.com:88path-1/",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//path-1",
       "script-src 'none'" },
     { "script-src http://www.example.com:88//path-1",
       "script-src 'none'" },
-    { "script-src http://www.example.com:88/.js",
-      "script-src 'none'" },
     { "script-src http://www.example.com:88.js",
       "script-src 'none'" },
     { "script-src http://www.example.com:*.js",
       "script-src 'none'" },
     { "script-src http://www.example.com:*.",
       "script-src 'none'" },
     { "connect-src http://www.example.com/foo%zz;",
       "connect-src 'none'" },
--- a/dom/bindings/BindingDeclarations.h
+++ b/dom/bindings/BindingDeclarations.h
@@ -87,17 +87,20 @@ public:
   bool Failed() const
   {
     return !Get();
   }
 
 protected:
   JS::Rooted<JSObject*> mGlobalJSObject;
   JSContext* mCx;
-  mutable nsISupports* mGlobalObject;
+  mutable nsISupports* MOZ_UNSAFE_REF("Valid because GlobalObject is a stack "
+                                      "class, and mGlobalObject points to the "
+                                      "global, so it won't be destroyed as long "
+                                      "as GlobalObject lives on the stack") mGlobalObject;
 };
 
 // Class for representing optional arguments.
 template<typename T, typename InternalType>
 class Optional_base
 {
 public:
   Optional_base()
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1608,54 +1608,52 @@ NativePropertyHooks sWorkerNativePropert
   prototypes::id::_ID_Count,
   constructors::id::_ID_Count,
   nullptr
 };
 
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
-                       JS::Value* vp)
+                       JS::MutableHandle<JS::Value> vp)
 {
   JS::Rooted<JSObject*> proto(cx);
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
     *found = false;
     return true;
   }
 
-  bool hasProp;
-  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
+  if (!JS_HasPropertyById(cx, proto, id, found)) {
     return false;
   }
 
-  *found = hasProp;
-  if (!hasProp || !vp) {
+  if (!*found) {
     return true;
   }
 
-  JS::Rooted<JS::Value> value(cx);
-  if (!JS_ForwardGetPropertyTo(cx, proto, id, proxy, &value)) {
-    return false;
-  }
-
-  *vp = value;
-  return true;
+  return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
 }
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<jsid> id)
+                       JS::Handle<jsid> id, bool* has)
 {
-  bool found;
-  // We ignore an error from GetPropertyOnPrototype.  We pass nullptr
-  // for vp so that GetPropertyOnPrototype won't actually do a get.
-  return !GetPropertyOnPrototype(cx, proxy, id, &found, nullptr) || found;
+  JS::Rooted<JSObject*> proto(cx);
+  if (!js::GetObjectProto(cx, proxy, &proto)) {
+    return false;
+  }
+  if (!proto) {
+    *has = false;
+    return true;
+  }
+
+  return JS_HasPropertyById(cx, proto, id, has);
 }
 
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties,
                        JS::AutoIdVector& props)
 {
@@ -1665,17 +1663,26 @@ AppendNamedPropertyIds(JSContext* cx, JS
       return false;
     }
 
     JS::Rooted<jsid> id(cx);
     if (!JS_ValueToId(cx, v, &id)) {
       return false;
     }
 
-    if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) {
+    bool shouldAppend = shadowPrototypeProperties;
+    if (!shouldAppend) {
+      bool has;
+      if (!HasPropertyOnPrototype(cx, proxy, id, &has)) {
+        return false;
+      }
+      shouldAppend = !has;
+    }
+
+    if (shouldAppend) {
       if (!props.append(id)) {
         return false;
       }
     }
   }
 
   return true;
 }
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1805,26 +1805,25 @@ bool
 UnforgeableValueOf(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 ThrowConstructorWithoutNew(JSContext* cx, const char* name);
 
-// vp is allowed to be null; in that case no get will be attempted,
-// and *found will simply indicate whether the property exists.
 bool
 GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id, bool* found,
-                       JS::Value* vp);
-
+                       JS::MutableHandle<JS::Value> vp);
+
+//
 bool
 HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
-                       JS::Handle<jsid> id);
+                       JS::Handle<jsid> id, bool* has);
 
 
 // Append the property names in "names" to "props". If
 // shadowPrototypeProperties is false then skip properties that are also
 // present on the proto chain of proxy.  If shadowPrototypeProperties is true,
 // then the "proxy" argument is ignored.
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -10099,25 +10099,51 @@ class CGDOMJSProxyHandler_getOwnPropDesc
                 # "arguments" as opposed to return type, [0] means first (and
                 # only) argument.
                 operations['NamedGetter'].signatures()[0][1][0].identifier.name)
             fillDescriptor = (
                 "FillPropertyDescriptor(desc, proxy, %s, %s);\n"
                 "return true;\n" % (readonly, enumerable))
             templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
-            condition = "!HasPropertyOnPrototype(cx, proxy, id)"
+
+            computeCondition = dedent("""
+                bool hasOnProto;
+                if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                  return false;
+                }
+                callNamedGetter = !hasOnProto;
+                """)
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                condition = "(!isXray || %s)" % condition
-            condition = "!ignoreNamedProps && " + condition
+                computeCondition = fill("""
+                    if (!isXray) {
+                      callNamedGetter = true;
+                    } else {
+                      $*{hasOnProto}
+                    }
+                    """,
+                    hasOnProto=computeCondition)
+
+            outerCondition = "!ignoreNamedProps"
             if self.descriptor.supportsIndexedProperties():
-                condition = "!IsArrayIndex(index) && " + condition
-            namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
-                                    condition).define() +
-                        "\n")
+                outerCondition = "!IsArrayIndex(index) && " + outerCondition
+
+            namedGet = fill("""
+                bool callNamedGetter = false;
+                if (${outerCondition}) {
+                  $*{computeCondition}
+                }
+                if (callNamedGetter) {
+                  $*{namedGetCode}
+                }
+                """,
+                outerCondition=outerCondition,
+                computeCondition=computeCondition,
+                namedGetCode=CGProxyNamedGetter(self.descriptor, templateValues).define())
+            namedGet += "\n"
         else:
             namedGet = ""
 
         return fill(
             """
             bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);
             $*{getIndexed}
             $*{getUnforgeable}
@@ -10340,18 +10366,26 @@ class CGDOMJSProxyHandler_delete(ClassMe
                 bool found = false;
                 $*{namedBody}
                 if (found) {
                   return true;
                 }
                 """,
                 namedBody=namedBody)
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                delete = CGIfWrapper(CGGeneric(delete),
-                                     "!HasPropertyOnPrototype(cx, proxy, id)").define()
+                delete = fill("""
+                    bool hasOnProto;
+                    if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                      return false;
+                    }
+                    if (!hasOnProto) {
+                      $*{delete}
+                    }
+                    """,
+                    delete=delete)
 
         delete += dedent("""
 
             return dom::DOMProxyHandler::delete_(cx, proxy, id, bp);
             """)
 
         return delete
 
@@ -10480,18 +10514,27 @@ class CGDOMJSProxyHandler_hasOwn(ClassMe
                 """
                 bool found = false;
                 $*{presenceChecker}
 
                 *bp = found;
                 """,
                 presenceChecker=CGProxyNamedPresenceChecker(self.descriptor, foundVar="found").define())
             if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
-                named = CGIfWrapper(CGGeneric(named + "return true;\n"),
-                                    "!HasPropertyOnPrototype(cx, proxy, id)").define()
+                named = fill("""
+                    bool hasOnProto;
+                    if (!HasPropertyOnPrototype(cx, proxy, id, &hasOnProto)) {
+                      return false;
+                    }
+                    if (!hasOnProto) {
+                      $*{protoLacksProperty}
+                      return true;
+                    }
+                    """,
+                    protoLacksProperty=named)
                 named += "*bp = false;\n"
             else:
                 named += "\n"
         else:
             named = "*bp = false;\n"
 
         return fill(
             """
@@ -10588,17 +10631,17 @@ class CGDOMJSProxyHandler_get(ClassMetho
             if self.descriptor.supportsIndexedProperties():
                 getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)")
             getNamed = getNamed.define() + "\n"
         else:
             getNamed = ""
 
         getOnPrototype = dedent("""
             bool foundOnPrototype;
-            if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp.address())) {
+            if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp)) {
               return false;
             }
 
             if (foundOnPrototype) {
               return true;
             }
 
             """)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -141,25 +141,32 @@ static const double THRESHOLD_LOW_PLAYBA
 // so we need to stay alive.
 // 2) If the element is not paused and playback has not ended, then
 // we will (or might) play, sending timeupdate and ended events and possibly
 // audio output, so we need to stay alive.
 // 3) if the element is seeking then we will fire seeking events and possibly
 // start playing afterward, so we need to stay alive.
 // 4) If autoplay could start playback in this element (if we got enough data),
 // then we need to stay alive.
-// 5) if the element is currently loading and not suspended,
-// script might be waiting for progress events or a 'suspend' event,
-// so we need to stay alive. If we're already suspended then (all other
-// conditions being met) it's OK to just disappear without firing any more
-// events, since we have the freedom to remain suspended indefinitely. Note
+// 5) if the element is currently loading, not suspended, and its source is
+// not a MediaSource, then script might be waiting for progress events or a
+// 'stalled' or 'suspend' event, so we need to stay alive.
+// If we're already suspended then (all other conditions being met),
+// it's OK to just disappear without firing any more events,
+// since we have the freedom to remain suspended indefinitely. Note
 // that we could use this 'suspended' loophole to garbage-collect a suspended
 // element in case 4 even if it had 'autoplay' set, but we choose not to.
 // If someone throws away all references to a loading 'autoplay' element
 // sound should still eventually play.
+// 6) If the source is a MediaSource, most loading events will not fire unless
+// appendBuffer() is called on a SourceBuffer, in which case something is
+// already referencing the SourceBuffer, which keeps the associated media
+// element alive. Further, a MediaSource will never time out the resource
+// fetch, and so should not keep the media element alive if it is
+// unreferenced. A pending 'stalled' event keeps the media element alive.
 //
 // Media elements owned by inactive documents (i.e. documents not contained in any
 // document viewer) should never hold a self-reference because none of the
 // above conditions are allowed: the element will stop loading and playing
 // and never resume loading or playing unless its owner document changes to
 // an active document (which can only happen if there is an external reference
 // to the element).
 // Media elements with no owner doc should be able to hold a self-reference.
@@ -679,32 +686,31 @@ void HTMLMediaElement::AbortExistingLoad
       // will now be reported as 0. The playback position was non-zero when
       // we destroyed the decoder, so fire a timeupdate event so that the
       // change will be reflected in the controls.
       FireTimeUpdate(false);
     }
     DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
   }
 
-  // We may have changed mPaused, mAutoplaying, mNetworkState and other
+  // We may have changed mPaused, mAutoplaying, and other
   // things which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
   mIsRunningSelectResource = false;
 }
 
 void HTMLMediaElement::NoSupportedMediaSourceError()
 {
   NS_ASSERTION(mNetworkState == NETWORK_LOADING,
                "Not loading during source selection?");
 
   mError = new MediaError(this, nsIDOMMediaError::MEDIA_ERR_SRC_NOT_SUPPORTED);
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE);
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
-  // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
   ChangeDelayLoadStatus(false);
 }
 
 typedef void (HTMLMediaElement::*SyncSectionFn)();
 
 // Runs a "synchronous section", a function that must run once the event loop
 // has reached a "stable state". See:
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#synchronous-section
@@ -809,26 +815,23 @@ void HTMLMediaElement::SelectResourceWra
 
 void HTMLMediaElement::SelectResource()
 {
   if (!mSrcAttrStream && !HasAttr(kNameSpaceID_None, nsGkAtoms::src) &&
       !HasSourceChildren(this)) {
     // The media element has neither a src attribute nor any source
     // element children, abort the load.
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
-    // This clears mDelayingLoadEvent, so AddRemoveSelfReference will be called
     ChangeDelayLoadStatus(false);
     return;
   }
 
   ChangeDelayLoadStatus(true);
 
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
-  // Load event was delayed, and still is, so no need to call
-  // AddRemoveSelfReference, since it must still be held
   DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
 
   // Delay setting mIsRunningSeletResource until after UpdatePreloadAction
   // so that we don't lose our state change by bailing out of the preload
   // state update
   UpdatePreloadAction();
   mIsRunningSelectResource = true;
 
@@ -2128,17 +2131,16 @@ void HTMLMediaElement::SetPlayedOrSeeked
 
 void
 HTMLMediaElement::ResetConnectionState()
 {
   SetCurrentTime(0);
   FireTimeUpdate(false);
   DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
-  AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
 }
 
 void
 HTMLMediaElement::Play(ErrorResult& aRv)
 {
   StopSuspendingAfterFirstFrame();
@@ -2853,17 +2855,16 @@ void HTMLMediaElement::SetupSrcMediaStre
   // Note: we must call DisconnectTrackListListeners(...)  before dropping
   // mSrcStream
   mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
 
   ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
   DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
   ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
-  AddRemoveSelfReference();
   // FirstFrameLoaded() will be called when the stream has current data.
 }
 
 void HTMLMediaElement::EndSrcMediaStreamPlayback()
 {
   MediaStream* stream = GetSrcMediaStream();
   if (stream) {
     stream->RemoveListener(mSrcStreamListener);
@@ -3005,17 +3006,16 @@ void HTMLMediaElement::Error(uint16_t aE
   mError = new MediaError(this, aErrorCode);
   DispatchAsyncEvent(NS_LITERAL_STRING("error"));
   if (mReadyState == nsIDOMHTMLMediaElement::HAVE_NOTHING) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     DispatchAsyncEvent(NS_LITERAL_STRING("emptied"));
   } else {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   }
-  AddRemoveSelfReference();
   ChangeDelayLoadStatus(false);
 }
 
 void HTMLMediaElement::PlaybackEnded()
 {
   // We changed state which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
@@ -3079,25 +3079,23 @@ void HTMLMediaElement::NotifySuspendedBy
 
 void HTMLMediaElement::DownloadSuspended()
 {
   if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING) {
     DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
   }
   if (mBegun) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
-    AddRemoveSelfReference();
   }
 }
 
 void HTMLMediaElement::DownloadResumed(bool aForceNetworkLoading)
 {
   if (mBegun || aForceNetworkLoading) {
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING);
-    AddRemoveSelfReference();
   }
 }
 
 void HTMLMediaElement::CheckProgress(bool aHaveNewProgress)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
 
@@ -3140,16 +3138,18 @@ void HTMLMediaElement::CheckProgress(boo
     DispatchAsyncEvent(NS_LITERAL_STRING("stalled"));
     ChangeDelayLoadStatus(false);
 
     NS_ASSERTION(mProgressTimer, "detected stalled without timer");
     // Stop timer events, which prevents repeated stalled events until there
     // is more progress.
     StopProgress();
   }
+
+  AddRemoveSelfReference();
 }
 
 /* static */
 void HTMLMediaElement::ProgressTimerCallback(nsITimer* aTimer, void* aClosure)
 {
   auto decoder = static_cast<HTMLMediaElement*>(aClosure);
   decoder->CheckProgress(false);
 }
@@ -3353,16 +3353,19 @@ void HTMLMediaElement::ChangeNetworkStat
     // Download is begun.
     mBegun = true;
     // Start progress notification when entering NETWORK_LOADING.
     StartProgress();
   } else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
     // Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
     DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
   }
+
+  // Changing mNetworkState affects AddRemoveSelfReference().
+  AddRemoveSelfReference();
 }
 
 bool HTMLMediaElement::CanActivateAutoplay()
 {
   // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
   // this element itself might be blocking the stream from making progress by
   // being paused.
   return !mPausedForInactiveDocumentOrChannel &&
@@ -3623,17 +3626,18 @@ void HTMLMediaElement::AddRemoveSelfRefe
   // boolean expression.
   bool needSelfReference = !mShuttingDown &&
     ownerDoc->IsActive() &&
     (mDelayingLoadEvent ||
      (!mPaused && mDecoder && !mDecoder->IsEnded()) ||
      (!mPaused && mSrcStream && !mSrcStream->IsFinished()) ||
      (mDecoder && mDecoder->IsSeeking()) ||
      CanActivateAutoplay() ||
-     mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING);
+     (mMediaSource ? mProgressTimer :
+      mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING));
 
   if (needSelfReference != mHasSelfReference) {
     mHasSelfReference = needSelfReference;
     if (needSelfReference) {
       // The observer service will hold a strong reference to us. This
       // will do to keep us alive. We need to know about shutdown so that
       // we can release our self-reference.
       nsContentUtils::RegisterShutdownObserver(this);
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -163,26 +163,17 @@ IDBRequest::SetLoggingSerialNumber(uint6
 
 void
 IDBRequest::CaptureCaller(nsAString& aFilename, uint32_t* aLineNo)
 {
   MOZ_ASSERT(aFilename.IsEmpty());
   MOZ_ASSERT(aLineNo);
 
   ThreadsafeAutoJSContext cx;
-
-  const char* filename = nullptr;
-  uint32_t lineNo = 0;
-  if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
-    *aLineNo = 0;
-    return;
-  }
-
-  aFilename.Assign(NS_ConvertUTF8toUTF16(filename));
-  *aLineNo = lineNo;
+  nsJSUtils::GetCallingLocation(cx, aFilename, aLineNo);
 }
 
 void
 IDBRequest::GetSource(
              Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const
 {
   AssertIsOnOwningThread();
 
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/AudioStreamTrack.h"
 #include "mozilla/dom/BlobEvent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/RecordErrorEvent.h"
 #include "mozilla/dom/VideoStreamTrack.h"
 #include "nsError.h"
 #include "nsIDocument.h"
+#include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsMimeTypes.h"
 #include "nsProxyRelease.h"
 #include "nsTArray.h"
 #include "GeckoProfiler.h"
 
 #ifdef LOG
 #undef LOG
@@ -540,32 +541,53 @@ private:
       TracksAvailableCallback* tracksAvailableCallback = new TracksAvailableCallback(this);
       domStream->OnTracksAvailable(tracksAvailableCallback);
     } else {
       // Web Audio node has only audio.
       InitEncoder(DOMMediaStream::HINT_CONTENTS_AUDIO);
     }
   }
 
+  bool Check3gppPermission()
+  {
+    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
+    if (!doc) {
+      return false;
+    }
+
+    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
+    doc->NodePrincipal()->GetAppStatus(&appStatus);
+
+    // Certified applications can always assign AUDIO_3GPP
+    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED) {
+      return true;
+    }
+
+    nsCOMPtr<nsIPermissionManager> pm =
+       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+
+    if (!pm) {
+      return false;
+    }
+
+    uint32_t perm = nsIPermissionManager::DENY_ACTION;
+    pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), "audio-capture:3gpp", &perm);
+    return perm == nsIPermissionManager::ALLOW_ACTION;
+  }
+
   void InitEncoder(uint8_t aTrackTypes)
   {
     LOG(PR_LOG_DEBUG, ("Session.InitEncoder %p", this));
     MOZ_ASSERT(NS_IsMainThread());
 
     // Allocate encoder and bind with union stream.
     // At this stage, the API doesn't allow UA to choose the output mimeType format.
 
-    nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
-    uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
-    if (doc) {
-      doc->NodePrincipal()->GetAppStatus(&appStatus);
-    }
-    // Only allow certificated application can assign AUDIO_3GPP
-    if (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
-         mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP)) {
+    // Make sure the application has permission to assign AUDIO_3GPP
+    if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && Check3gppPermission()) {
       mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP), aTrackTypes);
     } else {
       mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""), aTrackTypes);
     }
 
     if (!mEncoder) {
       DoSessionEndTask(NS_ERROR_ABORT);
       return;
--- a/dom/media/MediaRecorder.h
+++ b/dom/media/MediaRecorder.h
@@ -143,14 +143,16 @@ protected:
   nsTArray<nsRefPtr<Session> > mSessions;
   // It specifies the container format as well as the audio and video capture formats.
   nsString mMimeType;
 
 private:
   // Register MediaRecorder into Document to listen the activity changes.
   void RegisterActivityObserver();
   void UnRegisterActivityObserver();
+
+  bool Check3gppPermission();
 };
 
 }
 }
 
 #endif
--- a/dom/media/mediasource/MediaSource.cpp
+++ b/dom/media/mediasource/MediaSource.cpp
@@ -307,19 +307,22 @@ MediaSource::IsTypeSupported(const Globa
 }
 
 bool
 MediaSource::Attach(MediaSourceDecoder* aDecoder)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("MediaSource(%p)::Attach(aDecoder=%p) owner=%p", this, aDecoder, aDecoder->GetOwner());
   MOZ_ASSERT(aDecoder);
+  MOZ_ASSERT(aDecoder->GetOwner());
   if (mReadyState != MediaSourceReadyState::Closed) {
     return false;
   }
+  MOZ_ASSERT(!mMediaElement);
+  mMediaElement = aDecoder->GetOwner()->GetMediaElement();
   MOZ_ASSERT(!mDecoder);
   mDecoder = aDecoder;
   mDecoder->AttachMediaSource(this);
   SetReadyState(MediaSourceReadyState::Open);
   return true;
 }
 
 void
@@ -330,16 +333,17 @@ MediaSource::Detach()
             this, mDecoder.get(), mDecoder ? mDecoder->GetOwner() : nullptr);
   if (!mDecoder) {
     MOZ_ASSERT(mReadyState == MediaSourceReadyState::Closed);
     MOZ_ASSERT(mActiveSourceBuffers->IsEmpty() && mSourceBuffers->IsEmpty());
     return;
   }
   mDecoder->DetachMediaSource();
   mDecoder = nullptr;
+  mMediaElement = nullptr;
   mFirstSourceBufferInitialized = false;
   SetReadyState(MediaSourceReadyState::Closed);
   if (mActiveSourceBuffers) {
     mActiveSourceBuffers->Clear();
   }
   if (mSourceBuffers) {
     mSourceBuffers->Clear();
   }
@@ -482,16 +486,17 @@ MediaSource::GetParentObject() const
 
 JSObject*
 MediaSource::WrapObject(JSContext* aCx)
 {
   return MediaSourceBinding::Wrap(aCx, this);
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaSource, DOMEventTargetHelper,
+                                   mMediaElement,
                                    mSourceBuffers, mActiveSourceBuffers)
 
 NS_IMPL_ADDREF_INHERITED(MediaSource, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MediaSource, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaSource)
   NS_INTERFACE_MAP_ENTRY(mozilla::dom::MediaSource)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
--- a/dom/media/mediasource/MediaSource.h
+++ b/dom/media/mediasource/MediaSource.h
@@ -123,16 +123,19 @@ private:
   void DurationChange(double aOldDuration, double aNewDuration);
 
   void InitializationEvent();
 
   nsRefPtr<SourceBufferList> mSourceBuffers;
   nsRefPtr<SourceBufferList> mActiveSourceBuffers;
 
   nsRefPtr<MediaSourceDecoder> mDecoder;
+  // Ensures the media element remains alive to dispatch progress and
+  // durationchanged events.
+  nsRefPtr<HTMLMediaElement> mMediaElement;
 
   nsRefPtr<nsIPrincipal> mPrincipal;
 
   MediaSourceReadyState mReadyState;
 
   bool mFirstSourceBufferInitialized;
 };
 
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/dataChannel.js
@@ -0,0 +1,230 @@
+/* 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/. */
+
+function addInitialDataChannel(chain) {
+  chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
+    ['PC_LOCAL_CREATE_DATA_CHANNEL',
+      function (test) {
+        var channel = test.pcLocal.createDataChannel({});
+
+        is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
+        is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
+
+        is(test.pcLocal.signalingState, STABLE,
+           "Create datachannel does not change signaling state");
+
+        test.next();
+      }
+    ]
+  ]);
+  chain.insertAfter('PC_REMOTE_CREATE_ANSWER', [
+    [
+      'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcLocal, function () {
+          ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
+        },
+        // At this point a timeout failure will be of no value
+        null);
+        test.next();
+      }
+    ],
+    [
+      'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcRemote, function () {
+          ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
+        },
+        // At this point a timeout failure will be of no value
+        null);
+        test.next();
+      }
+    ]
+  ]);
+  chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', [
+    [
+      'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcLocal, function() {
+          test.next();
+        }, function() {
+          ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
+          //TODO: use stopAndExit() once bug 1019323 has landed
+          unexpectedEventAndFinish(this, 'timeout')
+          // to prevent test framework timeouts
+          test.next();
+        });
+      }
+    ],
+    [
+      'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
+      function (test) {
+        test.waitForInitialDataChannel(test.pcRemote, function() {
+          test.next();
+        }, function() {
+          ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
+          //TODO: use stopAndExit() once bug 1019323 has landed
+          unexpectedEventAndFinish(this, 'timeout');
+          // to prevent test framework timeouts
+          test.next();
+        });
+      }
+    ]
+  ]);
+  chain.removeAfter('PC_REMOTE_CHECK_ICE_CONNECTIONS');
+  chain.append([
+    [
+      'SEND_MESSAGE',
+      function (test) {
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_BLOB',
+      function (test) {
+        var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
+        var blob = new Blob(contents, { "type" : "text/plain" });
+
+        test.send(blob, function (channel, data) {
+          ok(data instanceof Blob, "Received data is of instance Blob");
+          is(data.size, blob.size, "Received data has the correct size.");
+
+          getBlobContent(data, function (recv_contents) {
+            is(recv_contents, contents, "Received data has the correct content.");
+
+            test.next();
+          });
+        });
+      }
+    ],
+    [
+      'CREATE_SECOND_DATA_CHANNEL',
+      function (test) {
+        test.createDataChannel({ }, function (sourceChannel, targetChannel) {
+          is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
+          is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
+
+          is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
+          is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
+      function (test) {
+        var channels = test.pcRemote.dataChannels;
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(channels.indexOf(channel), channels.length - 1, "Last channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
+      function (test) {
+        var message = "Message through 1st channel";
+        var options = {
+          sourceChannel: test.pcLocal.dataChannels[0],
+          targetChannel: test.pcRemote.dataChannels[0]
+        };
+
+        test.send(message, function (channel, data) {
+          is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        }, options);
+      }
+    ],
+    [
+      'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
+      function (test) {
+        var message = "Return a message also through 1st channel";
+        var options = {
+          sourceChannel: test.pcRemote.dataChannels[0],
+          targetChannel: test.pcLocal.dataChannels[0]
+        };
+
+        test.send(message, function (channel, data) {
+          is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
+          is(data, message, "Return message has the correct content.");
+
+          test.next();
+        }, options);
+      }
+    ],
+    [
+      'CREATE_NEGOTIATED_DATA_CHANNEL',
+      function (test) {
+        var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
+          maxRetransmits:500};
+        test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
+          is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
+          is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
+
+          is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
+          is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
+
+          if (options.id != undefined) {
+            is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
+          }
+          else {
+            options.id = sourceChannel2.id;
+          }
+          var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
+          is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
+          is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
+  /*
+    These aren't exposed by IDL yet
+          is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
+          is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
+       sourceChannel2.maxRetransmits);
+          is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
+       sourceChannel2.maxRetransmitTime);
+  */
+
+          is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
+          is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
+          is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
+  /*
+    These aren't exposed by IDL yet
+         is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
+          is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
+       targetChannel2.maxRetransmits);
+          is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
+       targetChannel2.maxRetransmitTime);
+  */
+
+          test.next();
+        });
+      }
+    ],
+    [
+      'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
+      function (test) {
+        var channels = test.pcRemote.dataChannels;
+        var message = "Lorem ipsum dolor sit amet";
+
+        test.send(message, function (channel, data) {
+          is(channels.indexOf(channel), channels.length - 1, "Last channel used");
+          is(data, message, "Received message has the correct content.");
+
+          test.next();
+        });
+      }
+    ]
+  ]);
+}
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 # strictContentSandbox - bug 1042735, Android 2.3 - bug 981881
 skip-if = (os == 'win' && strictContentSandbox) || android_version == '10'
 support-files =
   head.js
   constraints.js
+  dataChannel.js
   mediaStreamPlayback.js
   nonTrickleIce.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
   blacksilence.js
   turnConfig.js
 
--- a/dom/media/tests/mochitest/pc.js
+++ b/dom/media/tests/mochitest/pc.js
@@ -579,17 +579,17 @@ function PeerConnectionTest(options) {
 }
 
 /**
  * Closes the peer connection if it is active
  *
  * @param {Function} onSuccess
  *        Callback to execute when the peer connection has been closed successfully
  */
-PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
+PeerConnectionTest.prototype.closePC = function PCT_closePC(onSuccess) {
   info("Closing peer connections");
 
   var self = this;
   var closeTimeout = null;
   var waitingForLocal = false;
   var waitingForRemote = false;
   var everythingClosed = false;
 
@@ -651,16 +651,326 @@ PeerConnectionTest.prototype.close = fun
     // it is not a success, but the show must go on
     onSuccess();
   }, 60000);
 
   closeEverything();
 };
 
 /**
+ * Close the open data channels, followed by the underlying peer connection
+ *
+ * @param {Function} onSuccess
+ *        Callback to execute when all connections have been closed
+ */
+PeerConnectionTest.prototype.close = function PCT_close(onSuccess) {
+  var self = this;
+  var pendingDcClose = []
+  var closeTimeout = null;
+
+  info("PeerConnectionTest.close() called");
+
+  function _closePeerConnection() {
+    info("Now closing PeerConnection");
+    self.closePC.call(self, onSuccess);
+  }
+
+  function _closePeerConnectionCallback(index) {
+    info("_closePeerConnection called with index " + index);
+    var pos = pendingDcClose.indexOf(index);
+    if (pos != -1) {
+      pendingDcClose.splice(pos, 1);
+    }
+    else {
+      info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
+    }
+    if (pendingDcClose.length === 0) {
+      clearTimeout(closeTimeout);
+      _closePeerConnection();
+    }
+  }
+
+  var myDataChannels = null;
+  if (self.pcLocal) {
+    myDataChannels = self.pcLocal.dataChannels;
+  }
+  else if (self.pcRemote) {
+    myDataChannels = self.pcRemote.dataChannels;
+  }
+  var length = myDataChannels.length;
+  for (var i = 0; i < length; i++) {
+    var dataChannel = myDataChannels[i];
+    if (dataChannel.readyState !== "closed") {
+      pendingDcClose.push(i);
+      self.closeDataChannels(i, _closePeerConnectionCallback);
+    }
+  }
+  if (pendingDcClose.length === 0) {
+    _closePeerConnection();
+  }
+  else {
+    closeTimeout = setTimeout(function() {
+      ok(false, "Failed to properly close data channels: " +
+        pendingDcClose);
+      _closePeerConnection();
+    }, 60000);
+  }
+};
+
+/**
+ * Close the specified data channels
+ *
+ * @param {Number} index
+ *        Index of the data channels to close on both sides
+ * @param {Function} onSuccess
+ *        Callback to execute when the data channels has been closed
+ */
+PeerConnectionTest.prototype.closeDataChannels = function PCT_closeDataChannels(index, onSuccess) {
+  info("closeDataChannels called with index: " + index);
+  var localChannel = null;
+  if (this.pcLocal) {
+    localChannel = this.pcLocal.dataChannels[index];
+  }
+  var remoteChannel = null;
+  if (this.pcRemote) {
+    remoteChannel = this.pcRemote.dataChannels[index];
+  }
+
+  var self = this;
+  var wait = false;
+  var pollingMode = false;
+  var everythingClosed = false;
+  var verifyInterval = null;
+  var remoteCloseTimer = null;
+
+  function _allChannelsAreClosed() {
+    var ret = null;
+    if (localChannel) {
+      ret = (localChannel.readyState === "closed");
+    }
+    if (remoteChannel) {
+      if (ret !== null) {
+        ret = (ret && (remoteChannel.readyState === "closed"));
+      }
+      else {
+        ret = (remoteChannel.readyState === "closed");
+      }
+    }
+    return ret;
+  }
+
+  function verifyClosedChannels() {
+    if (everythingClosed) {
+      // safety protection against events firing late
+      return;
+    }
+    if (_allChannelsAreClosed()) {
+      ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
+      if (remoteCloseTimer !== null) {
+        clearTimeout(remoteCloseTimer);
+      }
+      if (verifyInterval !== null) {
+        clearInterval(verifyInterval);
+      }
+      everythingClosed = true;
+      onSuccess(index);
+    }
+    else {
+      info("Still waiting for DataChannel closure");
+    }
+  }
+
+  if ((localChannel) && (localChannel.readyState !== "closed")) {
+    // in case of steeplechase there is no far end, so we can only poll
+    if (remoteChannel) {
+      remoteChannel.onclose = function () {
+        is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
+        verifyClosedChannels();
+      };
+    }
+    else {
+      pollingMode = true;
+      verifyInterval = setInterval(verifyClosedChannels, 1000);
+    }
+
+    localChannel.close();
+    wait = true;
+  }
+  if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
+    if (localChannel) {
+      localChannel.onclose = function () {
+        is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
+        verifyClosedChannels();
+      };
+
+      // Apparently we are running a local test which has both ends of the
+      // data channel locally available, so by default lets wait for the
+      // remoteChannel.onclose handler from above to confirm closure on both
+      // ends.
+      remoteCloseTimer = setTimeout(function() {
+        todo(false, "localChannel.close() did not resulted in close signal on remote side");
+        remoteChannel.close();
+        verifyClosedChannels();
+      }, 30000);
+    }
+    else {
+      pollingMode = true;
+      verifyTimer = setInterval(verifyClosedChannels, 1000);
+
+      remoteChannel.close();
+    }
+
+    wait = true;
+  }
+
+  if (!wait) {
+    onSuccess(index);
+  }
+};
+
+
+/**
+ * Wait for the initial data channel to get into the open state
+ *
+ * @param {PeerConnectionWrapper} peer
+ *        The peer connection wrapper to run the command on
+ * @param {Function} onSuccess
+ *        Callback when the creation was successful
+ */
+PeerConnectionTest.prototype.waitForInitialDataChannel =
+        function PCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
+  var dcConnectionTimeout = null;
+  var dcOpened = false;
+
+  function dataChannelConnected(channel) {
+    // in case the switch statement below had called onSuccess already we
+    // don't want to call it again
+    if (!dcOpened) {
+      clearTimeout(dcConnectionTimeout);
+      is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
+      dcOpened = true;
+      onSuccess();
+    } else {
+      info("dataChannelConnected() called, but data channel was open already");
+    }
+  }
+
+  // TODO: drno: convert dataChannels into an object and make
+  //             registerDataChannelOpenEvent a generic function
+  if (peer == this.pcLocal) {
+    peer.dataChannels[0].onopen = dataChannelConnected;
+  } else {
+    peer.registerDataChannelOpenEvents(dataChannelConnected);
+  }
+
+  if (peer.dataChannels.length >= 1) {
+    // snapshot of the live value as it might change during test execution
+    const readyState = peer.dataChannels[0].readyState;
+    switch (readyState) {
+      case "open": {
+        is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
+        dcOpened = true;
+        onSuccess();
+        break;
+      }
+      case "connecting": {
+        is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
+        if (onFailure) {
+          dcConnectionTimeout = setTimeout(function () {
+            is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
+            onFailure();
+          }, 60000);
+        }
+        break;
+      }
+      default: {
+        ok(false, "dataChannels[0] is in unexpected state " + readyState);
+        if (onFailure) {
+          onFailure()
+        }
+      }
+    }
+  }
+};
+
+/**
+ * Send data (message or blob) to the other peer
+ *
+ * @param {String|Blob} data
+ *        Data to send to the other peer. For Blobs the MIME type will be lost.
+ * @param {Function} onSuccess
+ *        Callback to execute when data has been sent
+ * @param {Object} [options={ }]
+ *        Options to specify the data channels to be used
+ * @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
+ *        Data channel to use for sending the message
+ * @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
+ *        Data channel to use for receiving the message
+ */
+PeerConnectionTest.prototype.send = function PCT_send(data, onSuccess, options) {
+  options = options || { };
+  var source = options.sourceChannel ||
+           this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
+  var target = options.targetChannel ||
+           this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
+
+  // Register event handler for the target channel
+  target.onmessage = function (recv_data) {
+    onSuccess(target, recv_data);
+  };
+
+  source.send(data);
+};
+
+/**
+ * Create a data channel
+ *
+ * @param {Dict} options
+ *        Options for the data channel (see nsIPeerConnection)
+ * @param {Function} onSuccess
+ *        Callback when the creation was successful
+ */
+PeerConnectionTest.prototype.createDataChannel = function DCT_createDataChannel(options, onSuccess) {
+  var localChannel = null;
+  var remoteChannel = null;
+  var self = this;
+
+  // Method to synchronize all asynchronous events.
+  function check_next_test() {
+    if (localChannel && remoteChannel) {
+      onSuccess(localChannel, remoteChannel);
+    }
+  }
+
+  if (!options.negotiated) {
+    // Register handlers for the remote peer
+    this.pcRemote.registerDataChannelOpenEvents(function (channel) {
+      remoteChannel = channel;
+      check_next_test();
+    });
+  }
+
+  // Create the datachannel and handle the local 'onopen' event
+  this.pcLocal.createDataChannel(options, function (channel) {
+    localChannel = channel;
+
+    if (options.negotiated) {
+      // externally negotiated - we need to open from both ends
+      options.id = options.id || channel.id;  // allow for no id to let the impl choose
+      self.pcRemote.createDataChannel(options, function (channel) {
+        remoteChannel = channel;
+        check_next_test();
+      });
+    } else {
+      check_next_test();
+    }
+  });
+};
+
+/**
  * Executes the next command.
  */
 PeerConnectionTest.prototype.next = function PCT_next() {
   if (this._stepTimeout) {
     clearTimeout(this._stepTimeout);
     this._stepTimeout = null;
   }
   this.chain.executeNext();
@@ -990,382 +1300,16 @@ PCT_getSignalingMessage(messageType, onM
       info("invoking callback on message " + i + " from message queue, for message type:" + messageType);
       onMessage(this.signalingMessageQueue.splice(i, 1)[0]);
       return;
     }
   }
   this.registerSignalingCallback(messageType, onMessage);
 }
 
-/**
- * This class handles tests for data channels.
- *
- * @constructor
- * @param {object} [options={}]
- *        Optional options for the peer connection test
- * @param {object} [options.commands=commandsDataChannel]
- *        Commands to run for the test
- * @param {object} [options.config_local=undefined]
- *        Configuration for the local peer connection instance
- * @param {object} [options.config_remote=undefined]
- *        Configuration for the remote peer connection instance. If not defined
- *        the configuration from the local instance will be used
- */
-function DataChannelTest(options) {
-  options = options || { };
-  options.commands = options.commands || commandsDataChannel;
-
-  PeerConnectionTest.call(this, options);
-}
-
-DataChannelTest.prototype = Object.create(PeerConnectionTest.prototype, {
-  close : {
-    /**
-     * Close the open data channels, followed by the underlying peer connection
-     *
-     * @param {Function} onSuccess
-     *        Callback to execute when all connections have been closed
-     */
-    value : function DCT_close(onSuccess) {
-      var self = this;
-      var pendingDcClose = []
-      var closeTimeout = null;
-
-      info("DataChannelTest.close() called");
-
-      function _closePeerConnection() {
-        info("DataChannelTest closing PeerConnection");
-        PeerConnectionTest.prototype.close.call(self, onSuccess);
-      }
-
-      function _closePeerConnectionCallback(index) {
-        info("_closePeerConnection called with index " + index);
-        var pos = pendingDcClose.indexOf(index);
-        if (pos != -1) {
-          pendingDcClose.splice(pos, 1);
-        }
-        else {
-          info("_closePeerConnection index " + index + " is missing from pendingDcClose: " + pendingDcClose);
-        }
-        if (pendingDcClose.length === 0) {
-          clearTimeout(closeTimeout);
-          _closePeerConnection();
-        }
-      }
-
-      var myDataChannels = null;
-      if (self.pcLocal) {
-        myDataChannels = self.pcLocal.dataChannels;
-      }
-      else if (self.pcRemote) {
-        myDataChannels = self.pcRemote.dataChannels;
-      }
-      var length = myDataChannels.length;
-      for (var i = 0; i < length; i++) {
-        var dataChannel = myDataChannels[i];
-        if (dataChannel.readyState !== "closed") {
-          pendingDcClose.push(i);
-          self.closeDataChannels(i, _closePeerConnectionCallback);
-        }
-      }
-      if (pendingDcClose.length === 0) {
-        _closePeerConnection();
-      }
-      else {
-        closeTimeout = setTimeout(function() {
-          ok(false, "Failed to properly close data channels: " +
-            pendingDcClose);
-          _closePeerConnection();
-        }, 60000);
-      }
-    }
-  },
-
-  closeDataChannels : {
-    /**
-     * Close the specified data channels
-     *
-     * @param {Number} index
-     *        Index of the data channels to close on both sides
-     * @param {Function} onSuccess
-     *        Callback to execute when the data channels has been closed
-     */
-    value : function DCT_closeDataChannels(index, onSuccess) {
-      info("_closeDataChannels called with index: " + index);
-      var localChannel = null;
-      if (this.pcLocal) {
-        localChannel = this.pcLocal.dataChannels[index];
-      }
-      var remoteChannel = null;
-      if (this.pcRemote) {
-        remoteChannel = this.pcRemote.dataChannels[index];
-      }
-
-      var self = this;
-      var wait = false;
-      var pollingMode = false;
-      var everythingClosed = false;
-      var verifyInterval = null;
-      var remoteCloseTimer = null;
-
-      function _allChannelsAreClosed() {
-        var ret = null;
-        if (localChannel) {
-          ret = (localChannel.readyState === "closed");
-        }
-        if (remoteChannel) {
-          if (ret !== null) {
-            ret = (ret && (remoteChannel.readyState === "closed"));
-          }
-          else {
-            ret = (remoteChannel.readyState === "closed");
-          }
-        }
-        return ret;
-      }
-
-      function verifyClosedChannels() {
-        if (everythingClosed) {
-          // safety protection against events firing late
-          return;
-        }
-        if (_allChannelsAreClosed) {
-          ok(true, "DataChannel(s) have reached 'closed' state for data channel " + index);
-          if (remoteCloseTimer !== null) {
-            clearTimeout(remoteCloseTimer);
-          }
-          if (verifyInterval !== null) {
-            clearInterval(verifyInterval);
-          }
-          everythingClosed = true;
-          onSuccess(index);
-        }
-        else {
-          info("Still waiting for DataChannel closure");
-        }
-      }
-
-      if ((localChannel) && (localChannel.readyState !== "closed")) {
-        // in case of steeplechase there is no far end, so we can only poll
-        if (remoteChannel) {
-          remoteChannel.onclose = function () {
-            is(remoteChannel.readyState, "closed", "remoteChannel is in state 'closed'");
-            verifyClosedChannels();
-          };
-        }
-        else {
-          pollingMode = true;
-          verifyInterval = setInterval(verifyClosedChannels, 1000);
-        }
-
-        localChannel.close();
-        wait = true;
-      }
-      if ((remoteChannel) && (remoteChannel.readyState !== "closed")) {
-        if (localChannel) {
-          localChannel.onclose = function () {
-            is(localChannel.readyState, "closed", "localChannel is in state 'closed'");
-            verifyClosedChannels();
-          };
-
-          // Apparently we are running a local test which has both ends of the
-          // data channel locally available, so by default lets wait for the
-          // remoteChannel.onclose handler from above to confirm closure on both
-          // ends.
-          remoteCloseTimer = setTimeout(function() {
-            todo(false, "localChannel.close() did not resulted in close signal on remote side");
-            remoteChannel.close();
-            verifyClosedChannels();
-          }, 30000);
-        }
-        else {
-          pollingMode = true;
-          verifyTimer = setInterval(verifyClosedChannels, 1000);
-
-          remoteChannel.close();
-        }
-
-        wait = true;
-      }
-
-      if (!wait) {
-        onSuccess(index);
-      }
-    }
-  },
-
-  createDataChannel : {
-    /**
-     * Create a data channel
-     *
-     * @param {Dict} options
-     *        Options for the data channel (see nsIPeerConnection)
-     * @param {Function} onSuccess
-     *        Callback when the creation was successful
-     */
-    value : function DCT_createDataChannel(options, onSuccess) {
-      var localChannel = null;
-      var remoteChannel = null;
-      var self = this;
-
-      // Method to synchronize all asynchronous events.
-      function check_next_test() {
-        if (localChannel && remoteChannel) {
-          onSuccess(localChannel, remoteChannel);
-        }
-      }
-
-      if (!options.negotiated) {
-        // Register handlers for the remote peer
-        this.pcRemote.registerDataChannelOpenEvents(function (channel) {
-          remoteChannel = channel;
-          check_next_test();
-        });
-      }
-
-      // Create the datachannel and handle the local 'onopen' event
-      this.pcLocal.createDataChannel(options, function (channel) {
-        localChannel = channel;
-
-        if (options.negotiated) {
-          // externally negotiated - we need to open from both ends
-          options.id = options.id || channel.id;  // allow for no id to let the impl choose
-          self.pcRemote.createDataChannel(options, function (channel) {
-            remoteChannel = channel;
-            check_next_test();
-          });
-        } else {
-          check_next_test();
-        }
-      });
-    }
-  },
-
-  send : {
-    /**
-     * Send data (message or blob) to the other peer
-     *
-     * @param {String|Blob} data
-     *        Data to send to the other peer. For Blobs the MIME type will be lost.
-     * @param {Function} onSuccess
-     *        Callback to execute when data has been sent
-     * @param {Object} [options={ }]
-     *        Options to specify the data channels to be used
-     * @param {DataChannelWrapper} [options.sourceChannel=pcLocal.dataChannels[length - 1]]
-     *        Data channel to use for sending the message
-     * @param {DataChannelWrapper} [options.targetChannel=pcRemote.dataChannels[length - 1]]
-     *        Data channel to use for receiving the message
-     */
-    value : function DCT_send(data, onSuccess, options) {
-      options = options || { };
-      var source = options.sourceChannel ||
-               this.pcLocal.dataChannels[this.pcLocal.dataChannels.length - 1];
-      var target = options.targetChannel ||
-               this.pcRemote.dataChannels[this.pcRemote.dataChannels.length - 1];
-
-      // Register event handler for the target channel
-      target.onmessage = function (recv_data) {
-        onSuccess(target, recv_data);
-      };
-
-      source.send(data);
-    }
-  },
-
-  createOffer : {
-    value : function DCT_createOffer(peer, onSuccess) {
-      PeerConnectionTest.prototype.createOffer.call(this, peer, onSuccess);
-    }
-  },
-
-  setLocalDescription : {
-    /**
-     * Sets the local description for the specified peer connection instance
-     * and automatically handles the failure case.
-     *
-     * @param {PeerConnectionWrapper} peer
-              The peer connection wrapper to run the command on
-     * @param {mozRTCSessionDescription} desc
-     *        Session description for the local description request
-     * @param {function} onSuccess
-     *        Callback to execute if the local description was set successfully
-     */
-    value : function DCT_setLocalDescription(peer, desc, state, onSuccess) {
-      PeerConnectionTest.prototype.setLocalDescription.call(this, peer,
-                                                              desc, state, onSuccess);
-
-    }
-  },
-
-  waitForInitialDataChannel : {
-    /**
-     * Wait for the initial data channel to get into the open state
-     *
-     * @param {PeerConnectionWrapper} peer
-     *        The peer connection wrapper to run the command on
-     * @param {Function} onSuccess
-     *        Callback when the creation was successful
-     */
-    value : function DCT_waitForInitialDataChannel(peer, onSuccess, onFailure) {
-      var dcConnectionTimeout = null;
-      var dcOpened = false;
-
-      function dataChannelConnected(channel) {
-        // in case the switch statement below had called onSuccess already we
-        // don't want to call it again
-        if (!dcOpened) {
-          clearTimeout(dcConnectionTimeout);
-          is(channel.readyState, "open", peer + " dataChannels[0] switched to state: 'open'");
-          dcOpened = true;
-          onSuccess();
-        } else {
-          info("dataChannelConnected() called, but data channel was open already");
-        }
-      }
-
-      // TODO: drno: convert dataChannels into an object and make
-      //             registerDataChannelOpenEvent a generic function
-      if (peer == this.pcLocal) {
-        peer.dataChannels[0].onopen = dataChannelConnected;
-      } else {
-        peer.registerDataChannelOpenEvents(dataChannelConnected);
-      }
-
-      if (peer.dataChannels.length >= 1) {
-        // snapshot of the live value as it might change during test execution
-        const readyState = peer.dataChannels[0].readyState;
-        switch (readyState) {
-          case "open": {
-            is(readyState, "open", peer + " dataChannels[0] is already in state: 'open'");
-            dcOpened = true;
-            onSuccess();
-            break;
-          }
-          case "connecting": {
-            is(readyState, "connecting", peer + " dataChannels[0] is in state: 'connecting'");
-            if (onFailure) {
-              dcConnectionTimeout = setTimeout(function () {
-                is(peer.dataChannels[0].readyState, "open", peer + " timed out while waiting for dataChannels[0] to open");
-                onFailure();
-              }, 60000);
-            }
-            break;
-          }
-          default: {
-            ok(false, "dataChannels[0] is in unexpected state " + readyState);
-            if (onFailure) {
-              onFailure()
-            }
-          }
-        }
-      }
-    }
-  }
-
-});
 
 /**
  * This class acts as a wrapper around a DataChannel instance.
  *
  * @param dataChannel
  * @param peerConnectionWrapper
  * @constructor
  */
@@ -2569,27 +2513,28 @@ PeerConnectionWrapper.prototype = {
         if (!res.isRemote) {
           counters2[res.type] = toNum(counters2[res.type]) + 1;
         }
       });
     is(JSON.stringify(counters), JSON.stringify(counters2),
        "Spec and MapClass variant of RTCStatsReport enumeration agree");
     var nin = numTracks(this._pc.getRemoteStreams());
     var nout = numTracks(this._pc.getLocalStreams());
+    var ndata = this.dataChannels.length;
 
     // TODO(Bug 957145): Restore stronger inboundrtp test once Bug 948249 is fixed
     //is(toNum(counters["inboundrtp"]), nin, "Have " + nin + " inboundrtp stat(s)");
     ok(toNum(counters.inboundrtp) >= nin, "Have at least " + nin + " inboundrtp stat(s) *");
 
     is(toNum(counters.outboundrtp), nout, "Have " + nout + " outboundrtp stat(s)");
 
     var numLocalCandidates  = toNum(counters.localcandidate);
     var numRemoteCandidates = toNum(counters.remotecandidate);
     // If there are no tracks, there will be no stats either.
-    if (nin + nout > 0) {
+    if (nin + nout + ndata > 0) {
       ok(numLocalCandidates, "Have localcandidate stat(s)");
       ok(numRemoteCandidates, "Have remotecandidate stat(s)");
     } else {
       is(numLocalCandidates, 0, "Have no localcandidate stats");
       is(numRemoteCandidates, 0, "Have no remotecandidate stats");
     }
   },
 
@@ -2643,17 +2588,17 @@ PeerConnectionWrapper.prototype = {
    * @param {object} stats
    *        The stats to check for ICE candidate pairs
    * @param {object} counters
    *        The counters for media and data tracks based on constraints
    * @param {object} answer
    *        The SDP answer to check for SDP bundle support
    */
   checkStatsIceConnections : function PCW_checkStatsIceConnections(stats,
-      offerConstraintsList, offerOptions, numDataTracks, answer) {
+      offerConstraintsList, offerOptions, answer) {
     var numIceConnections = 0;
     Object.keys(stats).forEach(function(key) {
       if ((stats[key].type === "candidatepair") && stats[key].selected) {
         numIceConnections += 1;
       }
     });
     info("ICE connections according to stats: " + numIceConnections);
     if (answer.sdp.contains('a=group:BUNDLE')) {
@@ -2664,16 +2609,18 @@ PeerConnectionWrapper.prototype = {
       var numAudioTracks =
         this.countAudioTracksInMediaConstraint(offerConstraintsList) ||
         this.audioInOfferOptions(offerOptions);
 
       var numVideoTracks =
         this.countVideoTracksInMediaConstraint(offerConstraintsList) ||
         this.videoInOfferOptions(offerOptions);
 
+      var numDataTracks = this.dataChannels.length;
+
       var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks;
       info("expected audio + video + data tracks: " + numAudioVideoDataTracks);
       is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks");
     }
   },
 
   /**
    * Property-matching function for finding a certain stat in passed-in stats
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -530,30 +530,28 @@ var commandsPeerConnection = [
   ],
   [
     'PC_LOCAL_CHECK_ICE_CONNECTIONS',
     function (test) {
       test.pcLocal.getStats(null, function(stats) {
         test.pcLocal.checkStatsIceConnections(stats,
                                               test._offer_constraints,
                                               test._offer_options,
-                                              0,
                                               test.originalAnswer);
         test.next();
       });
     }
   ],
   [
     'PC_REMOTE_CHECK_ICE_CONNECTIONS',
     function (test) {
       test.pcRemote.getStats(null, function(stats) {
         test.pcRemote.checkStatsIceConnections(stats,
                                                test._offer_constraints,
                                                test._offer_options,
-                                               0,
                                                test.originalAnswer);
         test.next();
       });
     }
   ],
   [
     'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
     function (test) {
@@ -719,631 +717,8 @@ var commandsPeerConnection = [
         });
       } else {
         test.next();
       }
     }
   ]
 ];
 
-
-/**
- * Default list of commands to execute for a Datachannel test.
- */
-var commandsDataChannel = [
-  [
-    'PC_LOCAL_SETUP_ICE_LOGGER',
-    function (test) {
-      test.pcLocal.logIceConnectionState();
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_ICE_LOGGER',
-    function (test) {
-      test.pcRemote.logIceConnectionState();
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_SIGNALING_LOGGER',
-    function (test) {
-      test.pcLocal.logSignalingState();
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_SIGNALING_LOGGER',
-    function (test) {
-      test.pcRemote.logSignalingState();
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_GUM',
-    function (test) {
-      test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_INITIAL_SIGNALINGSTATE',
-    function (test) {
-      is(test.pcLocal.signalingState, STABLE,
-         "Initial local signalingState is stable");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_INITIAL_ICE_STATE',
-    function (test) {
-      is(test.pcLocal.iceConnectionState, ICE_NEW,
-        "Initial local ICE connection state is 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_GUM',
-    function (test) {
-      test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () {
-      test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_INITIAL_SIGNALINGSTATE',
-    function (test) {
-      is(test.pcRemote.signalingState, STABLE,
-         "Initial remote signalingState is stable");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_INITIAL_ICE_STATE',
-    function (test) {
-      is(test.pcRemote.iceConnectionState, ICE_NEW,
-        "Initial remote ICE connection state is 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_ICE_HANDLER',
-    function (test) {
-      test.pcLocal.setupIceCandidateHandler(test);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_ICE_HANDLER',
-    function (test) {
-      test.pcRemote.setupIceCandidateHandler(test);
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CREATE_DATA_CHANNEL',
-    function (test) {
-      var channel = test.pcLocal.createDataChannel({});
-
-      is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
-      is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
-
-      is(test.pcLocal.signalingState, STABLE,
-         "Create datachannel does not change signaling state");
-
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_CREATE_OFFER',
-    function (test) {
-      test.createOffer(test.pcLocal, function (offer) {
-        is(test.pcLocal.signalingState, STABLE,
-           "Local create offer does not change signaling state");
-        ok(offer.sdp.contains("m=application"),
-           "m=application is contained in the SDP");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_STEEPLECHASE_SIGNAL_OFFER',
-    function (test) {
-      if (test.steeplechase) {
-        send_message({"type": "offer",
-          "offer": test.originalOffer,
-          "offer_constraints": test.pcLocal.constraints,
-          "offer_options": test.pcLocal.offerOptions});
-        test._local_offer = test.originalOffer;
-        test._offer_constraints = test.pcLocal.constraints;
-        test._offer_options = test.pcLocal.offerOptions;
-      }
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SET_LOCAL_DESCRIPTION',
-    function (test) {
-      test.setLocalDescription(test.pcLocal, test.originalOffer, HAVE_LOCAL_OFFER,
-        function () {
-        is(test.pcLocal.signalingState, HAVE_LOCAL_OFFER,
-           "signalingState after local setLocalDescription is 'have-local-offer'");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_GET_OFFER',
-    function (test) {
-      if (!test.steeplechase) {
-        test._local_offer = test.originalOffer;
-        test._offer_constraints = test.pcLocal.constraints;
-        test._offer_options = test.pcLocal.offerOptions;
-        test.next();
-      } else {
-        test.getSignalingMessage("offer", function (message) {
-          ok("offer" in message, "Got an offer message");
-          test._local_offer = new mozRTCSessionDescription(message.offer);
-          test._offer_constraints = message.offer_constraints;
-          test._offer_options = message.offer_options;
-          test.next();
-        });
-      }
-    }
-  ],
-  [
-    'PC_REMOTE_SET_REMOTE_DESCRIPTION',
-    function (test) {
-      test.setRemoteDescription(test.pcRemote, test._local_offer, HAVE_REMOTE_OFFER,
-        function () {
-        is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
-           "signalingState after remote setRemoteDescription is 'have-remote-offer'");
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_SANE_LOCAL_SDP',
-    function (test) {
-      test.pcLocal.verifySdp(test._local_offer, "offer",
-        test._offer_constraints, test._offer_options,
-        function(trickle) {
-          test.pcLocal.localRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SANE_REMOTE_SDP',
-    function (test) {
-      test.pcRemote.verifySdp(test._local_offer, "offer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcRemote.remoteRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_CREATE_ANSWER',
-    function (test) {
-      test.createAnswer(test.pcRemote, function (answer) {
-        is(test.pcRemote.signalingState, HAVE_REMOTE_OFFER,
-           "Remote createAnswer does not change signaling state");
-        ok(answer.sdp.contains("m=application"),
-           "m=application is contained in the SDP");
-        if (test.steeplechase) {
-          send_message({"type":"answer",
-                        "answer": test.originalAnswer,
-                        "answer_constraints": test.pcRemote.constraints});
-          test._remote_answer = test.pcRemote._last_answer;
-          test._answer_constraints = test.pcRemote.constraints;
-        }
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_SETUP_DATA_CHANNEL_CALLBACK',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcLocal, function () {
-        ok(true, test.pcLocal + " dataChannels[0] switched to 'open'");
-      },
-      // At this point a timeout failure will be of no value
-      null);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SETUP_DATA_CHANNEL_CALLBACK',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcRemote, function () {
-        ok(true, test.pcRemote + " dataChannels[0] switched to 'open'");
-      },
-      // At this point a timeout failure will be of no value
-      null);
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_SET_LOCAL_DESCRIPTION',
-    function (test) {
-      test.setLocalDescription(test.pcRemote, test.originalAnswer, STABLE,
-        function () {
-          is(test.pcRemote.signalingState, STABLE,
-            "signalingState after remote setLocalDescription is 'stable'");
-          test.next();
-        }
-      );
-    }
-  ],
-  [
-    'PC_LOCAL_GET_ANSWER',
-    function (test) {
-      if (!test.steeplechase) {
-        test._remote_answer = test.originalAnswer;
-        test._answer_constraints = test.pcRemote.constraints;
-        test.next();
-      } else {
-        test.getSignalingMessage("answer", function (message) {
-          ok("answer" in message, "Got an answer message");
-          test._remote_answer = new mozRTCSessionDescription(message.answer);
-          test._answer_constraints = message.answer_constraints;
-          test.next();
-        });
-      }
-    }
-  ],
-  [
-    'PC_LOCAL_SET_REMOTE_DESCRIPTION',
-    function (test) {
-      test.setRemoteDescription(test.pcLocal, test._remote_answer, STABLE,
-        function () {
-          is(test.pcLocal.signalingState, STABLE,
-            "signalingState after local setRemoteDescription is 'stable'");
-          test.next();
-        }
-      );
-    }
-  ],
-  [
-    'PC_REMOTE_SANE_LOCAL_SDP',
-    function (test) {
-      test.pcRemote.verifySdp(test._remote_answer, "answer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcRemote.localRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_SANE_REMOTE_SDP',
-    function (test) {
-      test.pcLocal.verifySdp(test._remote_answer, "answer",
-        test._offer_constraints, test._offer_options,
-        function (trickle) {
-          test.pcLocal.remoteRequiresTrickleIce = trickle;
-        });
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_WAIT_FOR_ICE_CONNECTED',
-    function (test) {
-      var myTest = test;
-      var myPc = myTest.pcLocal;
-
-      function onIceConnectedSuccess () {
-        info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
-        ok(true, "pc_local: ICE switched to 'connected' state");
-        myTest.next();
-      };
-      function onIceConnectedFailed () {
-        dumpSdp(myTest);
-        ok(false, "pc_local: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
-        myTest.next();
-      };
-
-      if (myPc.isIceConnected()) {
-        info("pcLocal ICE connection state log: " + test.pcLocal.iceConnectionLog);
-        ok(true, "pc_local: ICE is in connected state");
-        myTest.next();
-      } else if (myPc.isIceConnectionPending()) {
-        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
-      } else {
-        dumpSdp(myTest);
-        ok(false, "pc_local: ICE is already in bad state: " + myPc.iceConnectionState);
-        myTest.next();
-      }
-    }
-  ],
-  [
-    'PC_LOCAL_VERIFY_ICE_GATHERING',
-    function (test) {
-      if (test.pcLocal.localRequiresTrickleIce) {
-        ok(test.pcLocal._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
-      }
-      isnot(test.pcLocal._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_REMOTE_WAIT_FOR_ICE_CONNECTED',
-    function (test) {
-      var myTest = test;
-      var myPc = myTest.pcRemote;
-
-      function onIceConnectedSuccess () {
-        info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
-        ok(true, "pc_remote: ICE switched to 'connected' state");
-        myTest.next();
-      };
-      function onIceConnectedFailed () {
-        dumpSdp(myTest);
-        ok(false, "pc_remote: ICE failed to switch to 'connected' state: " + myPc.iceConnectionState);
-        myTest.next();
-      };
-
-      if (myPc.isIceConnected()) {
-        info("pcRemote ICE connection state log: " + test.pcRemote.iceConnectionLog);
-        ok(true, "pc_remote: ICE is in connected state");
-        myTest.next();
-      } else if (myPc.isIceConnectionPending()) {
-        myPc.waitForIceConnected(onIceConnectedSuccess, onIceConnectedFailed);
-      } else {
-        dumpSdp(myTest);
-        ok(false, "pc_remote: ICE is already in bad state: " + myPc.iceConnectionState);
-        myTest.next();
-      }
-    }
-  ],
-  [
-    'PC_REMOTE_VERIFY_ICE_GATHERING',
-    function (test) {
-      if (test.pcRemote.localRequiresTrickleIce) {
-        ok(test.pcRemote._local_ice_candidates.length > 0, "Received local trickle ICE candidates");
-      }
-      isnot(test.pcRemote._pc.iceGatheringState, GATH_NEW, "ICE gathering state is not 'new'");
-      test.next();
-    }
-  ],
-  [
-    'PC_LOCAL_VERIFY_DATA_CHANNEL_STATE',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcLocal, function() {
-        test.next();
-      }, function() {
-        ok(false, test.pcLocal + " initial dataChannels[0] failed to switch to 'open'");
-        //TODO: use stopAndExit() once bug 1019323 has landed
-        unexpectedEventAndFinish(this, 'timeout')
-        // to prevent test framework timeouts
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_VERIFY_DATA_CHANNEL_STATE',
-    function (test) {
-      test.waitForInitialDataChannel(test.pcRemote, function() {
-        test.next();
-      }, function() {
-        ok(false, test.pcRemote + " initial dataChannels[0] failed to switch to 'open'");
-        //TODO: use stopAndExit() once bug 1019323 has landed
-        unexpectedEventAndFinish(this, 'timeout');
-        // to prevent test framework timeouts
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_MEDIA_TRACKS',
-    function (test) {
-      test.pcLocal.checkMediaTracks(test._answer_constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_MEDIA_TRACKS',
-    function (test) {
-      test.pcRemote.checkMediaTracks(test._offer_constraints, function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT',
-    function (test) {
-      test.pcLocal.checkMediaFlowPresent(function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT',
-    function (test) {
-      test.pcRemote.checkMediaFlowPresent(function () {
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_LOCAL_CHECK_ICE_CONNECTIONS',
-    function (test) {
-      test.pcLocal.getStats(null, function(stats) {
-        test.pcLocal.checkStatsIceConnections(stats,
-                                              test._offer_constraints,
-                                              test._offer_options,
-                                              1,
-                                              test.originalAnswer);
-        test.next();
-      });
-    }
-  ],
-  [
-    'PC_REMOTE_CHECK_ICE_CONNECTIONS',
-    function (test) {
-      test.pcRemote.getStats(null, function(stats) {
-        test.pcRemote.checkStatsIceConnections(stats,
-                                               test._offer_constraints,
-                                               test._offer_options,
-                                               1,
-                                               test.originalAnswer);
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE',
-    function (test) {
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(data, message, "Message correctly transmitted from pcLocal to pcRemote.");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_BLOB',
-    function (test) {
-      var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
-      var blob = new Blob(contents, { "type" : "text/plain" });
-
-      test.send(blob, function (channel, data) {
-        ok(data instanceof Blob, "Received data is of instance Blob");
-        is(data.size, blob.size, "Received data has the correct size.");
-
-        getBlobContent(data, function (recv_contents) {
-          is(recv_contents, contents, "Received data has the correct content.");
-
-          test.next();
-        });
-      });
-    }
-  ],
-  [
-    'CREATE_SECOND_DATA_CHANNEL',
-    function (test) {
-      test.createDataChannel({ }, function (sourceChannel, targetChannel) {
-        is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
-        is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
-
-        is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
-        is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL',
-    function (test) {
-      var channels = test.pcRemote.dataChannels;
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(channels.indexOf(channel), channels.length - 1, "Last channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_FIRST_CHANNEL',
-    function (test) {
-      var message = "Message through 1st channel";
-      var options = {
-        sourceChannel: test.pcLocal.dataChannels[0],
-        targetChannel: test.pcRemote.dataChannels[0]
-      };
-
-      test.send(message, function (channel, data) {
-        is(test.pcRemote.dataChannels.indexOf(channel), 0, "1st channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      }, options);
-    }
-  ],
-  [
-    'SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL',
-    function (test) {
-      var message = "Return a message also through 1st channel";
-      var options = {
-        sourceChannel: test.pcRemote.dataChannels[0],
-        targetChannel: test.pcLocal.dataChannels[0]
-      };
-
-      test.send(message, function (channel, data) {
-        is(test.pcLocal.dataChannels.indexOf(channel), 0, "1st channel used");
-        is(data, message, "Return message has the correct content.");
-
-        test.next();
-      }, options);
-    }
-  ],
-  [
-    'CREATE_NEGOTIATED_DATA_CHANNEL',
-    function (test) {
-      var options = {negotiated:true, id: 5, protocol:"foo/bar", ordered:false,
-        maxRetransmits:500};
-      test.createDataChannel(options, function (sourceChannel2, targetChannel2) {
-        is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
-        is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
-
-        is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
-        is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
-
-        if (options.id != undefined) {
-          is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
-        }
-        else {
-          options.id = sourceChannel2.id;
-        }
-        var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
-        is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
-        is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
-/*
-  These aren't exposed by IDL yet
-        is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
-        is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
-	   sourceChannel2.maxRetransmits);
-        is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
-	   sourceChannel2.maxRetransmitTime);
-*/
-
-        is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
-        is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
-        is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
-/*
-  These aren't exposed by IDL yet
-       is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
-        is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
-	   targetChannel2.maxRetransmits);
-        is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
-	   targetChannel2.maxRetransmitTime);
-*/
-
-        test.next();
-      });
-    }
-  ],
-  [
-    'SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2',
-    function (test) {
-      var channels = test.pcRemote.dataChannels;
-      var message = "Lorem ipsum dolor sit amet";
-
-      test.send(message, function (channel, data) {
-        is(channels.indexOf(channel), channels.length - 1, "Last channel used");
-        is(data, message, "Received message has the correct content.");
-
-        test.next();
-      });
-    }
-  ]
-];
-
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudio.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudio.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796895",
     title: "Basic data channel audio connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideo.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796891",
     title: "Basic data channel audio/video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true}, {video: true}],
                              [{audio: true}, {video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoCombined.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoCombined.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796891",
     title: "Basic data channel audio/video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{audio: true, video: true}],
                              [{audio: true, video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html
@@ -1,44 +1,44 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
-  SimpleTest.requestFlakyTimeout("untriaged");
-
   createHTML({
     bug: "1016476",
     title: "Basic data channel audio/video connection without bundle"
   });
 
   var test;
   runNetworkTest(function () {
-    test = new DataChannelTest();
-    test.setMediaConstraints([{audio: true}, {video: true}],
-                             [{audio: true}, {video: true}]);
+    test = new PeerConnectionTest();
+    addInitialDataChannel(test.chain);
     test.chain.insertAfter("PC_LOCAL_CREATE_OFFER",
       [[
         'PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER',
         function (test) {
           // Just replace a=group:BUNDLE with something that will be ignored.
           test.originalOffer.sdp = test.originalOffer.sdp.replace(
             "a=group:BUNDLE",
             "a=foo:");
           test.next();
         }
       ]]
       );
+    test.setMediaConstraints([{audio: true}, {video: true}],
+                             [{audio: true}, {video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicDataOnly.html
@@ -1,28 +1,30 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796894",
     title: "Basic datachannel only connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_basicVideo.html
+++ b/dom/media/tests/mochitest/test_dataChannel_basicVideo.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796889",
     title: "Basic data channel video connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     test.setMediaConstraints([{video: true}], [{video: true}]);
     test.run();
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_dataChannel_bug1013809.html
+++ b/dom/media/tests/mochitest/test_dataChannel_bug1013809.html
@@ -1,29 +1,31 @@
 <!DOCTYPE HTML>
 <html>
 <head>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="dataChannel.js"></script>
   <script type="application/javascript" src="head.js"></script>
   <script type="application/javascript" src="pc.js"></script>
   <script type="application/javascript" src="templates.js"></script>
   <script type="application/javascript" src="turnConfig.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     bug: "796895",
     title: "Basic data channel audio connection"
   });
 
   var test;
-  runNetworkTest(function () {
-    test = new DataChannelTest();
+  runNetworkTest(function (options) {
+    test = new PeerConnectionTest(options);
+    addInitialDataChannel(test.chain);
     var sld = test.chain.remove("PC_REMOTE_SET_LOCAL_DESCRIPTION");
     test.chain.insertAfter("PC_LOCAL_SET_REMOTE_DESCRIPTION", sld);
     test.setMediaConstraints([{audio: true}], [{audio: true}]);
     test.run();
   });
 
 </script>
 </pre>
--- a/dom/plugins/base/android/ANPAudio.cpp
+++ b/dom/plugins/base/android/ANPAudio.cpp
@@ -255,25 +255,25 @@ anp_audio_newTrack(uint32_t sampleRate, 
                                 s->rate,
                                 jChannels,
                                 jformat,
                                 s->bufferSize,
                                 MODE_STREAM);
 
   if (autoFrame.CheckForException() || obj == nullptr) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return nullptr;
   }
 
   jint state = jenv->CallIntMethod(obj, at.getstate);
 
   if (autoFrame.CheckForException() || state == STATE_UNINITIALIZED) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return nullptr;
   }
 
   s->output_unit = jenv->NewGlobalRef(obj);
   return s;
 }
 
 void
@@ -305,17 +305,17 @@ anp_audio_start(ANPAudioTrack* s)
 
   JNIEnv *jenv = GetJNIForThread();
 
   mozilla::AutoLocalJNIFrame autoFrame(jenv, 0);
   jenv->CallVoidMethod(s->output_unit, at.play);
 
   if (autoFrame.CheckForException()) {
     jenv->DeleteGlobalRef(s->at_class);
-    free(s);
+    delete s;
     return;
   }
 
   s->isStopped = false;
   s->keepGoing = true;
 
   // AudioRunnable now owns the ANPAudioTrack
   nsRefPtr<AudioRunnable> runnable = new AudioRunnable(s);
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -57,17 +57,20 @@ BrowserStreamChild::StreamConstructed(
   NPError rv = NPERR_NO_ERROR;
 
   *stype = NP_NORMAL;
   rv = mInstance->mPluginIface->newstream(
     &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
     &mStream, seekable, stype);
   if (rv != NPERR_NO_ERROR) {
     mState = DELETING;
-    mStreamNotify = nullptr;
+    if (mStreamNotify) {
+      mStreamNotify->SetAssociatedStream(nullptr);
+      mStreamNotify = nullptr;
+    }
   }
   else {
     mState = ALIVE;
   }
 
   return rv;
 }
 
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -2435,17 +2435,16 @@ StreamNotifyChild::ActorDestroy(ActorDes
         mBrowserStream = nullptr;
     }
 }
 
 
 void
 StreamNotifyChild::SetAssociatedStream(BrowserStreamChild* bs)
 {
-    NS_ASSERTION(bs, "Shouldn't be null");
     NS_ASSERTION(!mBrowserStream, "Two streams for one streamnotify?");
 
     mBrowserStream = bs;
 }
 
 bool
 StreamNotifyChild::Recv__delete__(const NPReason& reason)
 {
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -30,18 +30,19 @@
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
 #include "nsPrintfCString.h"
 #include "prsystem.h"
 #include "GeckoProfiler.h"
 #include "nsPluginTags.h"
 
 #ifdef XP_WIN
+#include "mozilla/widget/AudioSession.h"
+#include "nsWindowsHelpers.h"
 #include "PluginHangUIParent.h"
-#include "mozilla/widget/AudioSession.h"
 #endif
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "nsIProfiler.h"
 #include "nsIProfileSaveEvent.h"
 #endif
 
 #ifdef MOZ_WIDGET_GTK
@@ -2476,17 +2477,17 @@ PluginModuleChromeParent::InitializeInje
     if (kNotFound == lastSlash)
         return;
 
     if (!StringBeginsWith(Substring(path, lastSlash + 1),
                           NS_LITERAL_CSTRING(FLASH_PLUGIN_PREFIX)))
         return;
 
     TimeStamp th32Start = TimeStamp::Now();
-    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    nsAutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
     if (INVALID_HANDLE_VALUE == snapshot)
         return;
     TimeStamp th32End = TimeStamp::Now();
     mTimeBlocked += (th32End - th32Start);
 
     DWORD pluginProcessPID = GetProcessId(Process()->GetChildProcessHandle());
     mFlashProcess1 = GetFlashChildOfPID(pluginProcessPID, snapshot);
     if (mFlashProcess1) {
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -439,17 +439,17 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost
     // www.example.com/ should result in www.example.com/
     // please note that we do not have to perform any pct-decoding here
     // because we are just appending a '/' and not any actual chars.
     aCspHost->appendPath(NS_LITERAL_STRING("/"));
     return true;
   }
   // path can begin with "/" but not "//"
   // see http://tools.ietf.org/html/rfc3986#section-3.3
-  if (!hostChar()) {
+  if (peek(SLASH)) {
     const char16_t* params[] = { mCurToken.get() };
     logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource",
                              params, ArrayLength(params));
     return false;
   }
   return subPath(aCspHost);
 }
 
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -821,23 +821,26 @@ void NetworkUtils::startTethering(Comman
 {
   char command[MAX_COMMAND_SIZE];
 
   // We don't need to start tethering again.
   // Send the dummy command to continue the function chain.
   if (aResult.mResultReason.Find("started") != kNotFound) {
     snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND);
   } else {
-    snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
-
     // If usbStartIp/usbEndIp is not valid, don't append them since
     // the trailing white spaces will be parsed to extra empty args
     // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78
     if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) {
-      snprintf(command, MAX_COMMAND_SIZE - 1, "%s %s %s", command, GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp));
+      snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s %s %s",
+               GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp),
+               GET_CHAR(mUsbStartIp),  GET_CHAR(mUsbEndIp));
+    } else {
+      snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s",
+               GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp));
     }
   }
 
   doCommand(command, aChain, aCallback);
 }
 
 void NetworkUtils::untetherInterface(CommandChain* aChain,
                                      CommandCallback aCallback,
--- a/dom/tests/mochitest/webcomponents/mochitest.ini
+++ b/dom/tests/mochitest/webcomponents/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
 
 [test_bug900724.html]
 [test_bug1017896.html]
 [test_content_element.html]
 [test_custom_element_adopt_callbacks.html]
 [test_custom_element_callback_innerhtml.html]
 [test_custom_element_clone_callbacks.html]
 [test_custom_element_clone_callbacks_extended.html]
+[test_custom_element_import_node_created_callback.html]
 [test_nested_content_element.html]
 [test_dest_insertion_points.html]
 [test_dest_insertion_points_shadow.html]
 [test_fallback_dest_insertion_points.html]
 [test_detached_style.html]
 [test_dynamic_content_element_matching.html]
 [test_document_register.html]
 [test_document_register_base_queue.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/webcomponents/test_custom_element_import_node_created_callback.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1093680
+-->
+<head>
+  <title>Test created callback order for imported custom element.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<template id="template"><x-foo><span></span></x-foo></template>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1093680">Bug 1093680</a>
+<script>
+
+var fooProtoCreatedCallbackCalled = false;
+var fooProto = Object.create(HTMLElement.prototype);
+fooProto.createdCallback = function() {
+  ok(this.firstElementChild, "When the created callback is called, the element should already have a child because the callback should only be called after cloning all the contents.");
+  fooProtoCreatedCallbackCalled = true;
+};
+
+document.registerElement("x-foo", { prototype: fooProto });
+
+var template = document.getElementById("template");
+
+// Importing node will implicityly clone the conent in the main document.
+var adoptedFoo = document.importNode(template.content, true);
+
+ok(fooProtoCreatedCallbackCalled, "Created callback should be called after importing custom element into document");
+
+</script>
+</body>
+</html>
--- a/dom/webidl/HTMLAppletElement.webidl
+++ b/dom/webidl/HTMLAppletElement.webidl
@@ -7,17 +7,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#the-applet-element
  *
  * © 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.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-applet-element
-[NeedResolve]
+[NeedResolve, UnsafeInPrerendering]
 interface HTMLAppletElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString align;
   [Pure, SetterThrows]
            attribute DOMString alt;
   [Pure, SetterThrows]
            attribute DOMString archive;
   [Pure, SetterThrows]
--- a/dom/webidl/HTMLObjectElement.webidl
+++ b/dom/webidl/HTMLObjectElement.webidl
@@ -8,17 +8,17 @@
  * http://www.whatwg.org/specs/web-apps/current-work/#HTMLObjectElement-partial
  *
  * © 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.
  */
 
 // http://www.whatwg.org/specs/web-apps/current-work/#the-object-element
-[NeedResolve]
+[NeedResolve, UnsafeInPrerendering]
 interface HTMLObjectElement : HTMLElement {
   [Pure, SetterThrows]
            attribute DOMString data;
   [Pure, SetterThrows]
            attribute DOMString type;
   [Pure, SetterThrows]
            attribute boolean typeMustMatch;
   [Pure, SetterThrows]
--- a/dom/webidl/MozNFC.webidl
+++ b/dom/webidl/MozNFC.webidl
@@ -68,17 +68,18 @@ interface MozNFCManager {
   [CheckPermissions="nfc-manager", AvailableIn=CertifiedApps]
   Promise<void> powerOff();
 };
 
 [JSImplementation="@mozilla.org/nfc/manager;1",
  NavigatorProperty="mozNfc",
  Func="Navigator::HasNFCSupport",
  CheckPermissions="nfc nfc-share",
- AvailableIn="PrivilegedApps"]
+ AvailableIn="PrivilegedApps",
+ UnsafeInPrerendering]
 interface MozNFC : EventTarget {
   /**
    * Indicate if NFC is enabled.
    */
   readonly attribute boolean enabled;
 
   /**
    * This event will be fired when another NFCPeer is detected, and user confirms
--- a/dom/webidl/MozWifiManager.webidl
+++ b/dom/webidl/MozWifiManager.webidl
@@ -121,17 +121,18 @@ dictionary IPConfiguration {
   short maskLength;
   DOMString gateway;
   DOMString dns1;
   DOMString dns2;
 };
 
 [JSImplementation="@mozilla.org/wifimanager;1",
  NavigatorProperty="mozWifiManager",
- Func="Navigator::HasWifiManagerSupport"]
+ Func="Navigator::HasWifiManagerSupport",
+ UnsafeInPrerendering]
 interface MozWifiManager : EventTarget {
   /**
    * Turn on/off wifi functionality.
    * @param enable true for enable, false for disable.
    * onsuccess: Wifi enable/disable successfully, including no status change.
    * onerror: Wifi enable/disable failed or prohibited.
    */
   DOMRequest setWifiEnabled(boolean enabled);
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -188,17 +188,17 @@ partial interface Navigator {
   // WebKit/Blink supports this (hardcoded ""); Trident/Presto do not.
   readonly attribute DOMString vendorSub;
   // WebKit/Blink supports this (hardcoded "20030107"); Trident/Presto don't
   readonly attribute DOMString productSub;
   // WebKit/Blink/Trident/Presto support this.
   readonly attribute boolean cookieEnabled;
   [Throws]
   readonly attribute DOMString buildID;
-  [Throws, CheckPermissions="power"]
+  [Throws, CheckPermissions="power", UnsafeInPrerendering]
   readonly attribute MozPowerManager mozPower;
 
   // WebKit/Blink/Trident/Presto support this.
   [Throws]
   boolean javaEnabled();
 
   /**
    * Navigator requests to add an idle observer to the existing window.
@@ -235,17 +235,17 @@ partial interface Navigator {
    * all locks on the topic have been released.
    *
    * The returned MozWakeLock object is a token of the lock.  You can
    * unlock the lock via the object's |unlock| method.  The lock is released
    * automatically when its associated window is unloaded.
    *
    * @param aTopic resource name
    */
-  [Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport"]
+  [Throws, Pref="dom.wakelock.enabled", Func="Navigator::HasWakeLockSupport", UnsafeInPrerendering]
   MozWakeLock requestWakeLock(DOMString aTopic);
 };
 
 // nsIDOMNavigatorDeviceStorage
 partial interface Navigator {
   [Throws, Pref="device.storage.enabled"]
   DeviceStorage? getDeviceStorage(DOMString type);
   [Throws, Pref="device.storage.enabled"]
@@ -339,17 +339,17 @@ partial interface Navigator {
   [Throws, CheckPermissions="fmradio", UnsafeInPrerendering]
   readonly attribute FMRadio mozFMRadio;
 };
 #endif // MOZ_B2G_FM
 
 #ifdef MOZ_TIME_MANAGER
 // nsIDOMMozNavigatorTime
 partial interface Navigator {
-  [Throws, CheckPermissions="time"]
+  [Throws, CheckPermissions="time", UnsafeInPrerendering]
   readonly attribute MozTimeManager mozTime;
 };
 #endif // MOZ_TIME_MANAGER
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 // nsIMozNavigatorAudioChannelManager
 partial interface Navigator {
   [Throws]
--- a/dom/webidl/XULElement.webidl
+++ b/dom/webidl/XULElement.webidl
@@ -117,16 +117,19 @@ interface XULElement : Element {
 };
 
 // And the things from nsIFrameLoaderOwner
 [NoInterfaceObject]
 interface MozFrameLoaderOwner {
   [ChromeOnly]
   readonly attribute MozFrameLoader? frameLoader;
 
+  [ChromeOnly]
+  void setIsPrerendered();
+
   [ChromeOnly, Throws]
   void swapFrameLoaders(XULElement aOtherOwner);
 };
 
 XULElement implements GlobalEventHandlers;
 XULElement implements TouchEventHandlers;
 XULElement implements MozFrameLoaderOwner;
 XULElement implements OnErrorEventHandlerForNodes;
--- a/dom/wifi/WifiUtils.cpp
+++ b/dom/wifi/WifiUtils.cpp
@@ -8,17 +8,16 @@
 #include <cutils/properties.h>
 #include "prinit.h"
 #include "js/CharacterEncoding.h"
 
 using namespace mozilla::dom;
 
 #define BUFFER_SIZE        4096
 #define COMMAND_SIZE       256
-#define PROPERTY_VALUE_MAX 80
 
 // Intentionally not trying to dlclose() this handle. That's playing
 // Russian roulette with security bugs.
 static void* sWifiLib;
 static PRCallOnceType sInitWifiLib;
 
 static PRStatus
 InitWifiLib()
@@ -38,45 +37,45 @@ GetSharedLibrary()
 static bool
 GetWifiP2pSupported()
 {
   char propP2pSupported[PROPERTY_VALUE_MAX];
   property_get("ro.moz.wifi.p2p_supported", propP2pSupported, "0");
   return (0 == strcmp(propP2pSupported, "1"));
 }
 
-int
+static int
 hex2num(char c)
 {
   if (c >= '0' && c <= '9')
     return c - '0';
   if (c >= 'a' && c <= 'f')
     return c - 'a' + 10;
   if (c >= 'A' && c <= 'F')
     return c - 'A' + 10;
   return -1;
 }
 
-int
+static int
 hex2byte(const char* hex)
 {
   int a, b;
   a = hex2num(*hex++);
   if (a < 0)
     return -1;
   b = hex2num(*hex++);
   if (b < 0)
     return -1;
   return (a << 4) | b;
 }
 
 // This function is equivalent to printf_decode() at src/utils/common.c in
 // the supplicant.
 
-uint32_t
+static uint32_t
 convertToBytes(char* buf, uint32_t maxlen, const char* str)
 {
   const char *pos = str;
   uint32_t len = 0;
   int val;
 
   while (*pos) {
     if (len == maxlen)
@@ -151,17 +150,18 @@ convertToBytes(char* buf, uint32_t maxle
 }
 
 // This is the same algorithm as in InflateUTF8StringToBuffer with Copy and
 // while ignoring invalids.
 // https://mxr.mozilla.org/mozilla-central/source/js/src/vm/CharacterEncoding.cpp#231
 
 static const uint32_t REPLACE_UTF8 = 0xFFFD;
 
-void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
+static void
+LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aOut)
 {
   JS::UTF8Chars src(aInput, aLength);
 
   char16_t dst[aLength]; // Allocating for worst case.
 
   // Count how many char16_t characters are needed in the inflated string.
   // |i| is the index into |src|, and |j| is the the index into |dst|.
   size_t srclen = src.length();
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -5697,23 +5697,17 @@ WorkerPrivate::SetTimeout(JSContext* aCx
       extraArgVals.AppendElement(aArguments[index]);
     }
     newInfo->mExtraArgVals.SwapElements(extraArgVals);
   }
 
   newInfo->mTargetTime = TimeStamp::Now() + newInfo->mInterval;
 
   if (!newInfo->mTimeoutString.IsEmpty()) {
-    const char* filenameChars;
-    uint32_t lineNumber;
-    if (nsJSUtils::GetCallingLocation(aCx, &filenameChars, &lineNumber)) {
-      newInfo->mFilename = filenameChars;
-      newInfo->mLineNumber = lineNumber;
-    }
-    else {
+    if (!nsJSUtils::GetCallingLocation(aCx, newInfo->mFilename, &newInfo->mLineNumber)) {
       NS_WARNING("Failed to get calling location!");
     }
   }
 
   nsAutoPtr<TimeoutInfo>* insertedInfo =
     mTimeouts.InsertElementSorted(newInfo.forget(), GetAutoPtrComparator(mTimeouts));
 
   // If the timeout we just made is set to fire next then we need to update the
--- a/dom/xslt/xpath/txXPathOptimizer.cpp
+++ b/dom/xslt/xpath/txXPathOptimizer.cpp
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mozilla/Assertions.h"
 #include "txXPathOptimizer.h"
 #include "txExprResult.h"
 #include "nsIAtom.h"
 #include "nsGkAtoms.h"
 #include "txXPathNode.h"
 #include "txExpr.h"
 #include "txIXPathContext.h"
 
@@ -18,54 +19,44 @@ public:
         : mRecycler(aRecycler)
     {
     }
 
     // txIEvalContext
     nsresult getVariable(int32_t aNamespace, nsIAtom* aLName,
                          txAExprResult*& aResult)
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return NS_ERROR_FAILURE;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     bool isStripSpaceAllowed(const txXPathNode& aNode)
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return false;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     void* getPrivateContext()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return nullptr;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     txResultRecycler* recycler()
     {
         return mRecycler;
     }
     void receiveError(const nsAString& aMsg, nsresult aRes)
     {
     }
     const txXPathNode& getContextNode()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-
-        // This will return an invalid node, but we should never
-        // get here so that's fine.
-
-        return *static_cast<txXPathNode*>(nullptr);
+        MOZ_CRASH("shouldn't depend on this context");
     }
     uint32_t size()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return 1;
+        MOZ_CRASH("shouldn't depend on this context");
     }
     uint32_t position()
     {
-        NS_NOTREACHED("shouldn't depend on this context");
-        return 1;
+        MOZ_CRASH("shouldn't depend on this context");
     }
 
 private:
     txResultRecycler* mRecycler;
 };
 
 
 nsresult
--- a/dom/xul/nsXULElement.cpp
+++ b/dom/xul/nsXULElement.cpp
@@ -1598,16 +1598,22 @@ nsXULElement::LoadSrc()
     }
     nsXULSlots* slots = static_cast<nsXULSlots*>(Slots());
     if (!slots->mFrameLoader) {
         // false as the last parameter so that xul:iframe/browser/editor
         // session history handling works like dynamic html:iframes.
         // Usually xul elements are used in chrome, which doesn't have
         // session history at all.
         slots->mFrameLoader = nsFrameLoader::Create(this, false);
+        if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::prerendered,
+                        NS_LITERAL_STRING("true"), eIgnoreCase)) {
+            nsresult rv = slots->mFrameLoader->SetIsPrerendered();
+            NS_ENSURE_SUCCESS(rv,rv);
+        }
+
         NS_ENSURE_TRUE(slots->mFrameLoader, NS_OK);
     }
 
     return slots->mFrameLoader->LoadFrame();
 }
 
 nsresult
 nsXULElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
@@ -1623,16 +1629,23 @@ nsXULElement::GetFrameLoader()
     if (!slots)
         return nullptr;
 
     nsRefPtr<nsFrameLoader> loader = slots->mFrameLoader;
     return loader.forget();
 }
 
 nsresult
+nsXULElement::SetIsPrerendered()
+{
+  return SetAttr(kNameSpaceID_None, nsGkAtoms::prerendered, nullptr,
+                 NS_LITERAL_STRING("true"), true);
+}
+
+nsresult
 nsXULElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
 {
     nsCOMPtr<nsIContent> otherContent(do_QueryInterface(aOtherOwner));
     NS_ENSURE_TRUE(otherContent, NS_ERROR_NOT_IMPLEMENTED);
 
     nsXULElement* otherEl = FromContent(otherContent);
     NS_ENSURE_TRUE(otherEl, NS_ERROR_NOT_IMPLEMENTED);
 
--- a/dom/xul/nsXULElement.h
+++ b/dom/xul/nsXULElement.h
@@ -435,16 +435,17 @@ public:
 
     // nsIDOMXULElement
     NS_DECL_NSIDOMXULELEMENT
 
     virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
     virtual mozilla::EventStates IntrinsicState() const MOZ_OVERRIDE;
 
     nsresult GetFrameLoader(nsIFrameLoader** aFrameLoader);
+    nsresult SetIsPrerendered();
     nsresult SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner);
 
     virtual void RecompileScriptEventListeners() MOZ_OVERRIDE;
 
     // This function should ONLY be used by BindToTree implementations.
     // The function exists solely because XUL elements store the binding
     // parent as a member instead of in the slots, as Element does.
     void SetXULBindingParent(nsIContent* aBindingParent)
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/1061864.html
@@ -0,0 +1,8 @@
+<html>
+<body>
+<script>
+</script>
+<iframe id="childiframe" src="data:text/html,Test">
+</iframe>
+</body>
+</html>
--- a/dom/xul/test/chrome.ini
+++ b/dom/xul/test/chrome.ini
@@ -2,16 +2,17 @@
 support-files =
   398289-resource.xul
   bug497875-iframe.xul
   file_bug236853.rdf
   overlay1_bug335375.xul
   overlay2_bug335375.xul
   window_bug583948.xul
   window_bug757137.xul
+  1061864.html
 
 [test_bug199692.xul]
 [test_bug233643.xul]
 [test_bug236853.xul]
 [test_bug311681.xul]
 [test_bug335375.xul]
 [test_bug391002.xul]
 [test_bug398289.html]
@@ -21,10 +22,12 @@ support-files =
 [test_bug445177.xul]
 [test_bug449457.xul]
 [test_bug468176.xul]
 [test_bug497875.xul]
 [test_bug583948.xul]
 [test_bug640158_overlay_persist.xul]
 [test_bug757137.xul]
 [test_bug775972.xul]
+[test_bug1061864_1.xul]
+[test_bug1061864_2.xul]
 [test_bug1070049_throw_from_script.xul]
 [test_import_xul_to_content.xul]
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/test_bug1061864_1.xul
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
+-->
+<window title="Mozilla Bug 1061864"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 1061864 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function RunTest()
+  {
+    // Test that the docshell belonging to a prerendered frame loader will
+    // be created with the correct prerendered flag.
+    test(false, function() {
+      test(true, function() {
+        SimpleTest.finish();
+      });
+    });
+  }
+
+  function test(prerendered, callback) {
+    var parentIframe = document.createElement("iframe");
+    if (prerendered) {
+      parentIframe.setIsPrerendered();
+    }
+    parentIframe.onload = function() {
+      var docShell = parentIframe.frameLoader.docShell;
+      is(docShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
+      callback();
+    }
+    document.documentElement.appendChild(parentIframe);
+  }
+  ]]>
+  </script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
+     target="_blank">Mozilla Bug 1061864</a>
+  </body>
+</window>
new file mode 100644
--- /dev/null
+++ b/dom/xul/test/test_bug1061864_2.xul
@@ -0,0 +1,52 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1061864
+-->
+<window title="Mozilla Bug 1061864"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="RunTest();">
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+  <!-- test code goes here -->
+  <script type="application/javascript">
+  <![CDATA[
+
+  /** Test for Bug 1061864 **/
+  SimpleTest.waitForExplicitFinish();
+
+  function RunTest()
+  {
+    // Test that the docshell prerendered flag will be correctly inherited in
+    // prerendered documents.
+    test(false, function() {
+      test(true, function() {
+        SimpleTest.finish();
+      });
+    });
+  }
+
+  function test(prerendered, callback) {
+    var parentIframe = document.createElement("iframe");
+    if (prerendered) {
+      parentIframe.setIsPrerendered();
+    }
+    parentIframe.setAttribute("src", "1061864.html");
+    parentIframe.onload = function() {
+      var childIframe = parentIframe.contentDocument.getElementById("childiframe");
+      var childDocShell = childIframe.frameLoader.docShell;
+      is(childDocShell.isPrerendered, prerendered, "The docshell is" + (prerendered ? "" : " not") + " prerendered");
+      callback();
+    }
+    document.documentElement.appendChild(parentIframe);
+  }
+  ]]>
+  </script>
+
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1061864"
+     target="_blank">Mozilla Bug 1061864</a>
+  </body>
+</window>
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -520,21 +520,28 @@ GLScreenBuffer::Readback(SharedSurface* 
 
   bool needsSwap = src != SharedSurf();
   if (needsSwap) {
       SharedSurf()->UnlockProd();
       src->LockProd();
   }
 
   {
+      // Even though we're reading. We're doing it on
+      // the producer side. So we call ProducerAcquire
+      // instead of ConsumerAcquire.
+      src->ProducerAcquire();
+
       UniquePtr<ReadBuffer> buffer = CreateRead(src);
       MOZ_ASSERT(buffer);
 
       ScopedBindFramebuffer autoFB(mGL, buffer->mFB);
       ReadPixelsIntoDataSurface(mGL, dest);
+
+      src->ProducerRelease();
   }
 
   if (needsSwap) {
       src->UnlockProd();
       SharedSurf()->LockProd();
   }
 }
 
--- a/gfx/gl/SharedSurfaceIO.cpp
+++ b/gfx/gl/SharedSurfaceIO.cpp
@@ -97,50 +97,29 @@ SharedSurface_IOSurface::SharedSurface_I
                                                  const gfx::IntSize& size,
                                                  bool hasAlpha)
   : SharedSurface(SharedSurfaceType::IOSurface,
                   AttachmentType::GLTexture,
                   gl,
                   size,
                   hasAlpha)
   , mIOSurf(ioSurf)
-  , mCurConsGL(nullptr)
-  , mConsTex(0)
 {
     gl->MakeCurrent();
     mProdTex = 0;
     gl->fGenTextures(1, &mProdTex);
     BackTextureWithIOSurf(gl, mProdTex, mIOSurf);
 }
 
-GLuint
-SharedSurface_IOSurface::ConsTexture(GLContext* consGL)
-{
-    if (!mCurConsGL) {
-        mCurConsGL = consGL;
-    }
-    MOZ_ASSERT(consGL == mCurConsGL);
-
-    if (!mConsTex) {
-        consGL->MakeCurrent();
-        mConsTex = 0;
-        consGL->fGenTextures(1, &mConsTex);
-        BackTextureWithIOSurf(consGL, mConsTex, mIOSurf);
-    }
-
-    return mConsTex;
-}
-
 SharedSurface_IOSurface::~SharedSurface_IOSurface()
 {
     if (mProdTex) {
         DebugOnly<bool> success = mGL->MakeCurrent();
         MOZ_ASSERT(success);
         mGL->fDeleteTextures(1, &mProdTex);
-        mGL->fDeleteTextures(1, &mConsTex); // This will work if we're shared.
     }
 }
 
 ////////////////////////////////////////////////////////////////////////
 // SurfaceFactory_IOSurface
 
 /*static*/ UniquePtr<SurfaceFactory_IOSurface>
 SurfaceFactory_IOSurface::Create(GLContext* gl,
--- a/gfx/gl/SharedSurfaceIO.h
+++ b/gfx/gl/SharedSurfaceIO.h
@@ -41,39 +41,31 @@ public:
         return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
     }
 
     static SharedSurface_IOSurface* Cast(SharedSurface *surf) {
         MOZ_ASSERT(surf->mType == SharedSurfaceType::IOSurface);
         return static_cast<SharedSurface_IOSurface*>(surf);
     }
 
-    GLuint ConsTexture(GLContext* consGL);
-
-    GLenum ConsTextureTarget() const {
-        return LOCAL_GL_TEXTURE_RECTANGLE_ARB;
-    }
-
     MacIOSurface* GetIOSurface() const {
         return mIOSurf;
     }
 
     virtual bool NeedsIndirectReads() const MOZ_OVERRIDE {
         return true;
     }
 
 private:
     SharedSurface_IOSurface(const RefPtr<MacIOSurface>& ioSurf,
                             GLContext* gl, const gfx::IntSize& size,
                             bool hasAlpha);
 
     RefPtr<MacIOSurface> mIOSurf;
     GLuint mProdTex;
-    const GLContext* mCurConsGL;
-    GLuint mConsTex;
 };
 
 class SurfaceFactory_IOSurface : public SurfaceFactory
 {
 public:
     // Infallible.
     static UniquePtr<SurfaceFactory_IOSurface> Create(GLContext* gl,
                                                       const SurfaceCaps& caps);
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -160,18 +160,16 @@ enum SurfaceInitMode
  *  for each quad to be composited:
  *    call MakeCurrent if necessary (not necessary if no other context has been
  *      made current),
  *    take care of any texture upload required to composite the quad, this step
  *      is backend-dependent,
  *    construct an EffectChain for the quad,
  *    call DrawQuad,
  *  call EndFrame.
- * If the user has to stop compositing at any point before EndFrame, call
- * AbortFrame.
  * If the compositor is usually used for compositing but compositing is
  * temporarily done without the compositor, call EndFrameForExternalComposition
  * after compositing each frame so the compositor can remain internally
  * consistent.
  *
  * By default, the compositor will render to the screen, to render to a target,
  * call SetTargetContext or SetRenderTarget, the latter with a target created
  * by CreateRenderTarget or CreateRenderTargetFromSource.
@@ -351,21 +349,16 @@ public:
   /**
    * Post-rendering stuff if the rendering is done outside of this Compositor
    * e.g., by Composer2D.
    * aTransform is the transform from user space to window space.
    */
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) = 0;
 
   /**
-   * Tidy up if BeginFrame has been called, but EndFrame won't be.
-   */
-  virtual void AbortFrame() = 0;
-
-  /**
    * Setup the viewport and projection matrix for rendering to a target of the
    * given dimensions. The size and transform here will override those set in
    * BeginFrame. BeginFrame sets a size and transform for the default render
    * target, usually the screen. Calling this method prepares the compositor to
    * render using a different viewport (that is, size and transform), usually
    * associated with a new render target.
    */
   virtual void PrepareViewport(const gfx::IntSize& aSize) = 0;
--- a/gfx/layers/basic/BasicCompositor.cpp
+++ b/gfx/layers/basic/BasicCompositor.cpp
@@ -496,19 +496,10 @@ BasicCompositor::EndFrame()
   if (!mTarget) {
     mWidget->EndRemoteDrawing();
   }
 
   mDrawTarget = nullptr;
   mRenderTarget = nullptr;
 }
 
-void
-BasicCompositor::AbortFrame()
-{
-  mRenderTarget->mDrawTarget->PopClip();
-  mRenderTarget->mDrawTarget->PopClip();
-  mDrawTarget = nullptr;
-  mRenderTarget = nullptr;
-}
-
 }
 }
--- a/gfx/layers/basic/BasicCompositor.h
+++ b/gfx/layers/basic/BasicCompositor.h
@@ -95,17 +95,16 @@ public:
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE
   {
     NS_RUNTIMEABORT("We shouldn't ever hit this");
   }
-  virtual void AbortFrame() MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
   virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; }
   virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
   
   virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
   }
old mode 100644
new mode 100755
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -287,25 +287,29 @@ ContainerPrepare(ContainerT* aContainer,
   }
 
   CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
 
   /**
    * Setup our temporary surface for rendering the contents of this container.
    */
 
+  gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
+  if (surfaceRect.IsEmpty()) {
+    return;
+  }
+
   bool surfaceCopyNeeded;
   // DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call it unconditionally
   aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
   if (aContainer->UseIntermediateSurface()) {
     if (!surfaceCopyNeeded) {
       RefPtr<CompositingRenderTarget> surface = nullptr;
 
       RefPtr<CompositingRenderTarget>& lastSurf = aContainer->mLastIntermediateSurface;
-      gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
       if (lastSurf && !aContainer->mChildrenChanged && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
         surface = lastSurf;
       }
 
       if (!surface) {
         // If we don't need a copy we can render to the intermediate now to avoid
         // unecessary render target switching. This brings a big perf boost on mobile gpus.
         surface = CreateOrRecycleTarget(aContainer, aManager);
--- a/gfx/layers/d3d10/ImageLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ImageLayerD3D10.cpp
@@ -299,16 +299,18 @@ ImageLayerD3D10::RenderLayer()
 
     effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
       ShaderConstantRectD3D10(
         (float)yuvImage->GetData()->mPicX / yuvImage->GetData()->mYSize.width,
         (float)yuvImage->GetData()->mPicY / yuvImage->GetData()->mYSize.height,
         (float)yuvImage->GetData()->mPicSize.width / yuvImage->GetData()->mYSize.width,
         (float)yuvImage->GetData()->mPicSize.height / yuvImage->GetData()->mYSize.height)
        );
+  } else {
+    MOZ_CRASH("unexpected image format");
   }
 
   bool resetTexCoords = image->GetFormat() == ImageFormat::PLANAR_YCBCR;
   image = nullptr;
   autoLock.Unlock();
 
   technique->GetPassByIndex(0)->Apply(0);
   device()->Draw(4, 0);
--- a/gfx/layers/d3d11/CompositorD3D11.h
+++ b/gfx/layers/d3d11/CompositorD3D11.h
@@ -120,21 +120,16 @@ public:
 
   /**
    * Post rendering stuff if the rendering is outside of this Compositor
    * e.g., by Composer2D
    */
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
 
   /**
-   * Tidy up if BeginFrame has been called, but EndFrame won't be
-   */
-  virtual void AbortFrame() MOZ_OVERRIDE {}
-
-  /**
    * Setup the viewport and projection matrix for rendering
    * to a window of the given dimensions.
    */
   virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
 
 #ifdef MOZ_DUMP_PAINTING
--- a/gfx/layers/d3d9/CompositorD3D9.h
+++ b/gfx/layers/d3d9/CompositorD3D9.h
@@ -64,18 +64,16 @@ public:
                           const gfx::Rect& aRenderBounds,
                           gfx::Rect *aClipRectOut = nullptr,
                           gfx::Rect *aRenderBoundsOut = nullptr) MOZ_OVERRIDE;
 
   virtual void EndFrame() MOZ_OVERRIDE;
 
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE {}
 
-  virtual void AbortFrame() MOZ_OVERRIDE {}
-
   virtual void PrepareViewport(const gfx::IntSize& aSize) MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE{ return true; }
 
 #ifdef MOZ_DUMP_PAINTING
   virtual const char* Name() const MOZ_OVERRIDE { return "Direct3D9"; }
 #endif
 
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -194,16 +194,17 @@ static Thread* CompositorThread() {
 static void SetThreadPriority()
 {
   hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
 }
 
 CompositorVsyncObserver::CompositorVsyncObserver(CompositorParent* aCompositorParent, nsIWidget* aWidget)
   : mNeedsComposite(false)
   , mIsObservingVsync(false)
+  , mVsyncNotificationsSkipped(0)
   , mCompositorParent(aCompositorParent)
   , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
   , mCurrentCompositeTask(nullptr)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWidget != nullptr);
   mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher();
 #ifdef MOZ_WIDGET_GONK
@@ -280,16 +281,19 @@ CompositorVsyncObserver::Composite(TimeS
   {
     MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
     mCurrentCompositeTask = nullptr;
   }
 
   if (mNeedsComposite && mCompositorParent) {
     mNeedsComposite = false;
     mCompositorParent->CompositeCallback(aVsyncTimestamp);
+    mVsyncNotificationsSkipped = 0;
+  } else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
+    UnobserveVsync();
   }
 
   DispatchTouchEvents(aVsyncTimestamp);
 }
 
 bool
 CompositorVsyncObserver::NeedsComposite()
 {
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -112,16 +112,17 @@ private:
   void Composite(TimeStamp aVsyncTimestamp);
   void NotifyCompositeTaskExecuted();
   void ObserveVsync();
   void UnobserveVsync();
   void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
 
   bool mNeedsComposite;
   bool mIsObservingVsync;
+  int32_t mVsyncNotificationsSkipped;
   nsRefPtr<CompositorParent> mCompositorParent;
   nsRefPtr<CompositorVsyncDispatcher> mCompositorVsyncDispatcher;
 
   mozilla::Monitor mCurrentCompositeTaskMonitor;
   CancelableTask* mCurrentCompositeTask;
 };
 
 class CompositorParent MOZ_FINAL : public PCompositorParent,
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -571,17 +571,17 @@ CompositorOGL::BeginFrame(const nsIntReg
                           const Rect *aClipRectIn,
                           const Rect& aRenderBounds,
                           Rect *aClipRectOut,
                           Rect *aRenderBoundsOut)
 {
   PROFILER_LABEL("CompositorOGL", "BeginFrame",
     js::ProfileEntry::Category::GRAPHICS);
 
-  MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
+  MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame");
 
   mFrameInProgress = true;
   gfx::Rect rect;
   if (mUseExternalSurfaceSize) {
     rect = gfx::Rect(0, 0, mSurfaceSize.width, mSurfaceSize.height);
   } else {
     rect = gfx::Rect(aRenderBounds.x, aRenderBounds.y, aRenderBounds.width, aRenderBounds.height);
   }
@@ -1318,28 +1318,16 @@ CompositorOGL::EndFrameForExternalCompos
     mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
   }
   if (mTexturePool) {
     mTexturePool->EndFrame();
   }
 }
 
 void
-CompositorOGL::AbortFrame()
-{
-  mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
-  mFrameInProgress = false;
-  mCurrentRenderTarget = nullptr;
-
-  if (mTexturePool) {
-    mTexturePool->EndFrame();
-  }
-}
-
-void
 CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize)
 {
   mSurfaceSize.width = aSize.width;
   mSurfaceSize.height = aSize.height;
 }
 
 void
 CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform)
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -234,17 +234,16 @@ public:
                         const EffectChain &aEffectChain,
                         gfx::Float aOpacity,
                         const gfx::Matrix4x4 &aTransform) MOZ_OVERRIDE;
 
   virtual void EndFrame() MOZ_OVERRIDE;
   virtual void SetFBAcquireFence(Layer* aLayer) MOZ_OVERRIDE;
   virtual FenceHandle GetReleaseFence() MOZ_OVERRIDE;
   virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) MOZ_OVERRIDE;
-  virtual void AbortFrame() MOZ_OVERRIDE;
 
   virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE;
 
   virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE
   {
     if (!mGLContext)
       return false;
     int32_t maxSize = GetMaxTextureSize();
--- a/gfx/src/nsRegion.h
+++ b/gfx/src/nsRegion.h
@@ -14,16 +14,17 @@
 #include "nsCoord.h"                    // for nscoord
 #include "nsError.h"                    // for nsresult
 #include "nsPoint.h"                    // for nsIntPoint, nsPoint
 #include "nsRect.h"                     // for nsIntRect, nsRect
 #include "nsMargin.h"                   // for nsIntMargin
 #include "nsStringGlue.h"               // for nsCString
 #include "xpcom-config.h"               // for CPP_THROW_NEW
 #include "mozilla/TypedEnum.h"          // for the VisitEdges typed enum
+#include "mozilla/Move.h"               // for mozilla::Move
 
 class nsIntRegion;
 class gfx3DMatrix;
 
 #include "pixman.h"
 
 /* For information on the internal representation look at pixman-region.c
  *
@@ -56,16 +57,23 @@ class nsRegion
 public:
   nsRegion () { pixman_region32_init(&mImpl); }
   MOZ_IMPLICIT nsRegion (const nsRect& aRect) { pixman_region32_init_rect(&mImpl,
                                                                           aRect.x,
                                                                           aRect.y,
                                                                           aRect.width,
                                                                           aRect.height); }
   nsRegion (const nsRegion& aRegion) { pixman_region32_init(&mImpl); pixman_region32_copy(&mImpl,aRegion.Impl()); }
+  nsRegion (nsRegion&& aRegion) { mImpl = aRegion.mImpl; pixman_region32_init(&aRegion.mImpl); }
+  nsRegion& operator = (nsRegion&& aRegion) {
+      pixman_region32_fini(&mImpl);
+      mImpl = aRegion.mImpl;
+      pixman_region32_init(&aRegion.mImpl);
+      return *this;
+  }
  ~nsRegion () { pixman_region32_fini(&mImpl); }
   nsRegion& operator = (const nsRect& aRect) { Copy (aRect); return *this; }
   nsRegion& operator = (const nsRegion& aRegion) { Copy (aRegion); return *this; }
   bool operator==(const nsRegion& aRgn) const
   {
     return IsEqual(aRgn);
   }
   bool operator!=(const nsRegion& aRgn) const
@@ -456,18 +464,20 @@ class NS_GFX nsIntRegion
 {
   friend class nsIntRegionRectIterator;
   friend class nsRegion;
 
 public:
   nsIntRegion () {}
   MOZ_IMPLICIT nsIntRegion (const nsIntRect& aRect) : mImpl (ToRect(aRect)) {}
   nsIntRegion (const nsIntRegion& aRegion) : mImpl (aRegion.mImpl) {}
+  nsIntRegion (nsIntRegion&& aRegion) : mImpl (mozilla::Move(aRegion.mImpl)) {}
   nsIntRegion& operator = (const nsIntRect& aRect) { mImpl = ToRect (aRect); return *this; }
   nsIntRegion& operator = (const nsIntRegion& aRegion) { mImpl = aRegion.mImpl; return *this; }
+  nsIntRegion& operator = (nsIntRegion&& aRegion) { mImpl = mozilla::Move(aRegion.mImpl); return *this; }
 
   bool operator==(const nsIntRegion& aRgn) const
   {
     return IsEqual(aRgn);
   }
   bool operator!=(const nsIntRegion& aRgn) const
   {
     return !(*this == aRgn);
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -214,16 +214,19 @@ private:
   DECL_GFX_PREF(Live, "gfx.perf-warnings.enabled",             PerfWarnings, bool, false);
   DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs",           WorkAroundDriverBugs, bool, true);
 
   DECL_GFX_PREF(Live, "gfx.draw-color-bars",                   CompositorDrawColorBars, bool, false);
 
   // Use vsync events generated by hardware
   DECL_GFX_PREF(Once, "gfx.vsync.hw-vsync.enabled",            HardwareVsyncEnabled, bool, false);
   DECL_GFX_PREF(Once, "gfx.vsync.compositor",                  VsyncAlignedCompositor, bool, false);
+  // On b2g, in really bad cases, I've seen up to 80 ms delays between touch events and the main thread
+  // processing them. So 80 ms / 16 = 5 vsync events. Double it up just to be on the safe side, so 10.
+  DECL_GFX_PREF(Once, "gfx.vsync.compositor.unobserve-count",  CompositorUnobserveCount, int32_t, 10);
   DECL_GFX_PREF(Once, "gfx.touch.resample",                    TouchResampling, bool, false);
   // These times should be in milliseconds
   DECL_GFX_PREF(Once, "gfx.touch.resample.max-predict",        TouchResampleMaxPredict, int32_t, 8);
   DECL_GFX_PREF(Once, "gfx.touch.resample.vsync-adjust",       TouchVsyncSampleAdjust, int32_t, 5);
   DECL_GFX_PREF(Once, "gfx.touch.resample.delay-threshold",    TouchResampleVsyncDelayThreshold, int32_t, 20);
   DECL_GFX_PREF(Once, "gfx.touch.resample.old-touch-threshold",TouchResampleOldTouchThreshold, int32_t, 17);
 
   DECL_GFX_PREF(Live, "gl.msaa-level",                         MSAALevel, uint32_t, 2);
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -433,46 +433,62 @@ HandleFault(PEXCEPTION_POINTERS exceptio
     EXCEPTION_RECORD *record = exception->ExceptionRecord;
     CONTEXT *context = exception->ContextRecord;
 
     if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
         return false;
 
     uint8_t **ppc = ContextToPC(context);
     uint8_t *pc = *ppc;
-    MOZ_ASSERT(pc == record->ExceptionAddress);
 
     if (record->NumberParameters < 2)
         return false;
 
     // Don't allow recursive handling of signals, see AutoSetHandlingSignal.
     JSRuntime *rt = RuntimeForCurrentThread();
     if (!rt || rt->handlingSignal)
         return false;
     AutoSetHandlingSignal handling(rt);
 
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
     if (!activation)
         return false;
 
+# if defined(JS_CODEGEN_X64)
     const AsmJSModule &module = activation->module();
-    if (!module.containsFunctionPC(pc))
-        return false;
 
-# if defined(JS_CODEGEN_X64)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     void *faultingAddress = (void*)record->ExceptionInformation[1];
     if (!module.maybeHeap() ||
         faultingAddress < module.maybeHeap() ||
         faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
     {
         return false;
     }
 
+    if (!module.containsFunctionPC(pc)) {
+        // On Windows, it is possible for InterruptRunningCode to execute
+        // between a faulting heap access and the handling of the fault due
+        // to InterruptRunningCode's use of SuspendThread. When this happens,
+        // after ResumeThread, the exception handler is called with pc equal to
+        // module.interruptExit, which is logically wrong. The Right Thing would
+        // be for the OS to make fault-handling atomic (so that CONTEXT.pc was
+        // always the logically-faulting pc). Fortunately, we can detect this
+        // case and silence the exception ourselves (the exception will
+        // retrigger after the interrupt jumps back to resumePC).
+        if (pc == module.interruptExit() &&
+            module.containsFunctionPC(activation->resumePC()) &&
+            module.lookupHeapAccess(activation->resumePC()))
+        {
+            return true;
+        }
+        return false;
+    }
+
     const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc);
     if (!heapAccess)
         return false;
 
     // Also not necessary, but, since we can, do.
     if (heapAccess->isLoad() != !record->ExceptionInformation[0])
         return false;
 
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1,12 +1,53 @@
 /* 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/. */
 
+// ES6 draft rev30 (2014/12/24) 22.2.3.7 %TypedArray%.prototype.every(callbackfn[, thisArg]).
+function TypedArrayEvery(callbackfn, thisArg = undefined) {
+    // This function is not generic.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
+                            "TypedArrayEvery");
+    }
+
+    // Steps 1-2.
+    var O = this;
+
+    // Steps 3-5.
+    var len = TypedArrayLength(O);
+
+    // Step 6.
+    if (arguments.length === 0)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.every");
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+
+    // Step 7.
+    var T = thisArg;
+
+    // Steps 8-9.
+    // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
+    for (var k = 0; k < len; k++) {
+        // Steps 9.d.i-9.d.ii.
+        var kValue = O[k];
+
+        // Steps 9.d.iii-9.d.iv.
+        var testResult = callFunction(callbackfn, T, kValue, k, O);
+
+        // Step 9.d.v.
+        if (!testResult)
+            return false;
+    }
+
+    // Step 10.
+    return true;
+}
+
 // ES6 draft rev29 (2014/12/06) 22.2.3.8 %TypedArray%.prototype.fill(value [, start [, end ]])
 function TypedArrayFill(value, start = 0, end = undefined) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, value, start, end,
                             "TypedArrayFill");
     }
 
@@ -278,16 +319,57 @@ function TypedArrayReverse() {
         O[lower] = upperValue;
         O[upper] = lowerValue;
     }
 
     // Step 9.
     return O;
 }
 
+// ES6 draft rev30 (2014/12/24) 22.2.3.25 %TypedArray%.prototype.some(callbackfn[, thisArg]).
+function TypedArraySome(callbackfn, thisArg = undefined) {
+    // This function is not generic.
+    if (!IsObject(this) || !IsTypedArray(this)) {
+        return callFunction(CallTypedArrayMethodIfWrapped, this, callbackfn, thisArg,
+                            "TypedArraySome");
+    }
+
+    // Steps 1-2.
+    var O = this;
+
+    // Steps 3-5.
+    var len = TypedArrayLength(O);
+
+    // Step 6.
+    if (arguments.length === 0)
+        ThrowError(JSMSG_MISSING_FUN_ARG, 0, "%TypedArray%.prototype.some");
+    if (!IsCallable(callbackfn))
+        ThrowError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn));
+
+    // Step 7.
+    var T = thisArg;
+
+    // Steps 8-9.
+    // Omit steps 9.a-9.c and the 'if' clause in step 9.d, since there are no holes in typed arrays.
+    for (var k = 0; k < len; k++) {
+        // Steps 9.d.i-9.d.ii.
+        var kValue = O[k];
+
+        // Steps 9.d.iii-9.d.iv.
+        var testResult = callFunction(callbackfn, T, kValue, k, O);
+
+        // Step 9.d.v.
+        if (testResult)
+            return true;
+    }
+
+    // Step 10.
+    return false;
+}
+
 // Proposed for ES7:
 // https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
 function TypedArrayIncludes(searchElement, fromIndex = 0) {
     // This function is not generic.
     if (!IsObject(this) || !IsTypedArray(this)) {
         return callFunction(CallTypedArrayMethodIfWrapped, this, searchElement,
                             fromIndex, "TypedArrayIncludes");
     }
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -115,21 +115,23 @@ MarkExactStackRootsAcrossTypes(T context
     MarkExactStackRootList<Value, MarkValueRoot>(trc, context, "exact-value");
     MarkExactStackRootList<types::Type, MarkTypeRoot>(trc, context, "types::Type");
     MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
     MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
         trc, context, "JSPropertyDescriptor");
     MarkExactStackRootList<PropDesc, MarkPropDescRoot>(trc, context, "PropDesc");
 }
 
+#ifdef JSGC_FJGENERATIONAL
 static void
 MarkExactStackRoots(ThreadSafeContext* cx, JSTracer *trc)
 {
     MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx, trc);
 }
+#endif
 
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
 {
     for (ContextIter cx(rt); !cx.done(); cx.next())
         MarkExactStackRootsAcrossTypes<ThreadSafeContext*>(cx.get(), trc);
     MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
 }
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -292,17 +292,17 @@ static const size_t PHASE_DAG_NONE = 0;
 // read-only memory anyway.)
 struct ExtraPhaseInfo
 {
     // Depth in the tree of each phase type
     size_t depth;
 
     // Index into the set of parallel arrays of timing data, for parents with
     // at least one multi-parented child
-    int dagSlot;
+    size_t dagSlot;
 };
 
 static const Phase PHASE_NO_PARENT = PHASE_LIMIT;
 
 struct DagChildEdge {
     Phase parent;
     Phase child;
 } dagChildEdges[] = {
@@ -377,17 +377,17 @@ static const PhaseInfo phases[] = {
         { PHASE_MARK_CCWS, "Mark Cross Compartment Wrappers", PHASE_MARK_ROOTS },
         { PHASE_MARK_ROOTERS, "Mark Rooters", PHASE_MARK_ROOTS },
         { PHASE_MARK_RUNTIME_DATA, "Mark Runtime-wide Data", PHASE_MARK_ROOTS },
         { PHASE_MARK_EMBEDDING, "Mark Embedding", PHASE_MARK_ROOTS },
         { PHASE_MARK_COMPARTMENTS, "Mark Compartments", PHASE_MARK_ROOTS },
     { PHASE_LIMIT, nullptr, PHASE_NO_PARENT }
 };
 
-ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
+static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
 
 // Mapping from all nodes with a multi-parented child to a Vector of all
 // multi-parented children and their descendants. (Single-parented children will
 // not show up in this list.)
 static mozilla::Vector<Phase> dagDescendants[Statistics::MAX_MULTIPARENT_PHASES + 1];
 
 struct AllPhaseIterator {
     int current;
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -77,17 +77,17 @@ static const int kWordRanges[] = {
 static const int kWordRangeCount = ArrayLength(kWordRanges);
 static const int kDigitRanges[] = { '0', '9' + 1, 0x10000 };
 static const int kDigitRangeCount = ArrayLength(kDigitRanges);
 static const int kSurrogateRanges[] = { 0xd800, 0xe000, 0x10000 };
 static const int kSurrogateRangeCount = ArrayLength(kSurrogateRanges);
 static const int kLineTerminatorRanges[] = { 0x000A, 0x000B, 0x000D, 0x000E,
     0x2028, 0x202A, 0x10000 };
 static const int kLineTerminatorRangeCount = ArrayLength(kLineTerminatorRanges);
-static const unsigned kMaxOneByteCharCode = 0xff;
+static const int kMaxOneByteCharCode = 0xff;
 static const int kMaxUtf16CodeUnit = 0xffff;
 
 static char16_t
 MaximumCharacter(bool ascii)
 {
     return ascii ? kMaxOneByteCharCode : kMaxUtf16CodeUnit;
 }
 
@@ -3175,17 +3175,17 @@ SplitSearchSpace(RangeBoundaryVector &ra
     // 128-character space can take up a lot of space in the ranges array if,
     // for example, we only want to match every second character (eg. the lower
     // case characters on some Unicode pages).
     int binary_chop_index = (end_index + start_index) / 2;
     // The first test ensures that we get to the code that handles the ASCII
     // range with a single not-taken branch, speeding up this important
     // character range (even non-ASCII charset-based text has spaces and
     // punctuation).
-    if (*border - 1 > (int) kMaxOneByteCharCode &&  // ASCII case.
+    if (*border - 1 > kMaxOneByteCharCode &&  // ASCII case.
         end_index - start_index > (*new_start_index - start_index) * 2 &&
         last - first > kSize * 2 &&
         binary_chop_index > *new_start_index &&
         ranges[binary_chop_index] >= first + 2 * kSize)
     {
         int scan_forward_for_section_border = binary_chop_index;;
         int new_border = (ranges[binary_chop_index] | kMask) + 1;
 
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -513,17 +513,17 @@ RegExpParser<CharT>::ScanForCaptures()
     widechar n;
     while ((n = current()) != kEndMarker) {
         Advance();
         switch (n) {
           case '\\':
             Advance();
             break;
           case '[': {
-            int c;
+            widechar c;
             while ((c = current()) != kEndMarker) {
                 Advance();
                 if (c == '\\') {
                     Advance();
                 } else {
                     if (c == ']') break;
                 }
             }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1117235.js
@@ -0,0 +1,8 @@
+load(libdir + "asserts.js");
+
+if (helperThreadCount() === 0)
+  quit(0);
+
+options('werror');
+offThreadCompileScript("function f() {'use asm'}");
+assertThrowsInstanceOf(()=>runOffThreadScript(), TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1117255.js
@@ -0,0 +1,14 @@
+function f(stdlib, foreign, buffer) {
+    "use asm";
+    var i32 = new stdlib.Int32Array(buffer);
+    function g(i) {
+        i=i|0;
+        var j=0;
+        for (; (j>>>0) < 100000; j=(j+1)|0)
+            i32[i>>2] = j;
+    }
+    return g
+}
+var g = f(this, null, new ArrayBuffer(1<<16));
+timeout(.1, function cb() { return true });
+g(1<<16);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/collections/iterator-noSuchMethod.js
@@ -0,0 +1,24 @@
+// __noSuchMethod__ is totally non-standard and evil, but in this one weird case
+// below we don't actually use it.  So this test is bog-standard ES6, not
+// SpiderMonkey-specific.
+//
+// In ES6:
+//   Accessing 1[Symbol.iterator]() throws a TypeError calling |undefined|.
+// In SpiderMonkey:
+//   Accessing 1[Symbol.iterator]() does *not* invoke __noSuchMethod__ looked up
+//   on 1 (or on an implicitly boxed 1), because 1 is a primitive value.
+//   SpiderMonkey then does exactly the ES6 thing here and throws a TypeError
+//   calling |undefined|.
+
+Object.prototype.__noSuchMethod__ = {};
+
+try
+{
+  var [x] = 1;
+  throw new Error("didn't throw");
+}
+catch (e)
+{
+  assertEq(e instanceof TypeError, true,
+           "expected TypeError, got " + e);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1116103.js
@@ -0,0 +1,11 @@
+// |jit-test| error: ReferenceError
+
+evaluate(`
+    var g = newGlobal();
+    g.parent = this;
+    g.eval('new Debugger(parent).onExceptionUnwind = function() {};');
+`)
+{
+    while (x && 0) {}
+    let x
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1113139.js
@@ -0,0 +1,9 @@
+var lfcode = new Array();
+lfcode.push = function(x) { eval("(function() { " + x + " })();"); };
+lfcode.push("\
+function error(str) { try { eval(str); } catch (e) { return e; } }\
+const YIELD_PAREN = error('(function*(){(for (y of (yield 1, 2)) y)})').message;\
+const GENEXP_YIELD = error('(function*(){(for (x of yield 1) x)})').message;\
+const GENERIC = error('(for)').message;\
+const eval = [];\
+");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyConstruct5.js
@@ -0,0 +1,14 @@
+load(libdir + "asserts.js");
+
+// Make sure that a proxy only has a [[Construct]] if the target does
+
+var handler = {};
+var p = new Proxy(Math.sin, handler);
+var r = Proxy.revocable(Math.sin, handler).proxy;
+
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
+// Better throw regardless of whether we have a handler trap.
+handler.construct = (() => ({}));
+assertThrowsInstanceOf(() => new p, TypeError, "Can't use 'new' on proxy with non-constructor target");
+assertThrowsInstanceOf(() => new r, TypeError, "Can't use 'new' on proxy with non-constructor target");
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -200,31 +200,30 @@ CollectJitStackScripts(JSContext *cx, co
                 // it points into the debug mode OSR handler and cannot be
                 // used to look up a corresponding ICEntry.
                 //
                 // See cases F and G in PatchBaselineFramesForDebugMode.
                 if (!entries.append(DebugModeOSREntry(script, info)))
                     return false;
             } else {
                 uint8_t *retAddr = iter.returnAddressToFp();
-                ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr);
-                if (icEntry) {
-                    // Normally, the frame is settled on a pc with an ICEntry.
-                    if (!entries.append(DebugModeOSREntry(script, *icEntry)))
+                if (iter.baselineFrame()->isDebuggerHandlingException()) {
+                    // We are in the middle of handling an exception. This
+                    // happens since we could have bailed out in place from
+                    // Ion after a throw, settling on the pc which may have no
+                    // ICEntry (e.g., Ion is free to insert resume points
+                    // after non-effectful ops for better register
+                    // allocation).
+                    jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
+                    if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
                         return false;
                 } else {
-                    // Otherwise, we are in the middle of handling an
-                    // exception. This happens since we could have bailed out
-                    // in place from Ion after a throw, settling on the pc
-                    // which may have no ICEntry (e.g., Ion is free to insert
-                    // resume points after non-effectful ops for better
-                    // register allocation).
-                    MOZ_ASSERT(iter.baselineFrame()->isDebuggerHandlingException());
-                    jsbytecode *pc = script->baselineScript()->pcForNativeAddress(script, retAddr);
-                    if (!entries.append(DebugModeOSREntry(script, script->pcToOffset(pc))))
+                    // Normally, the frame is settled on a pc with an ICEntry.
+                    ICEntry &icEntry = script->baselineScript()->icEntryFromReturnAddress(retAddr);
+                    if (!entries.append(DebugModeOSREntry(script, icEntry)))
                         return false;
                 }
             }
 
             if (entries.back().needsRecompileInfo()) {
                 if (!entries.back().allocateRecompileInfo(cx))
                     return false;
 
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -1064,17 +1064,17 @@ TypeAnalyzer::adjustPhiInputs(MPhi *phi)
         if (in->type() == MIRType_Value)
             continue;
 
         if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) {
             // The input is being explicitly unboxed, so sneak past and grab
             // the original box.
             phi->replaceOperand(i, in->toUnbox()->input());
         } else {
-            MDefinition *box = BoxInputsPolicy::alwaysBoxAt(alloc(), in->block()->lastIns(), in);
+            MDefinition *box = AlwaysBoxAt(alloc(), in->block()->lastIns(), in);
             phi->replaceOperand(i, box);
         }
     }
 }
 
 bool
 TypeAnalyzer::adjustInputs(MDefinition *def)
 {
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -4384,37 +4384,38 @@ NameIC::update(JSContext *cx, size_t cac
     cache.getScriptedLocation(&script, &pc);
 
     RootedObject obj(cx);
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
         return false;
 
+    // Look first. Don't generate cache entries if the lookup fails.
+    if (cache.isTypeOf()) {
+        if (!FetchName<true>(cx, obj, holder, name, shape, vp))
+            return false;
+    } else {
+        if (!FetchName<false>(cx, obj, holder, name, shape, vp))
+            return false;
+    }
+
     if (cache.canAttachStub()) {
         if (IsCacheableNameReadSlot(scopeChain, obj, holder, shape, pc, cache.outputReg())) {
             if (!cache.attachReadSlot(cx, outerScript, ion, scopeChain, obj,
                                       holder.as<NativeObject>(), shape))
             {
                 return false;
             }
         } else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
             if (!cache.attachCallGetter(cx, outerScript, ion, scopeChain, obj, holder, shape, returnAddr))
                 return false;
         }
     }
 
-    if (cache.isTypeOf()) {
-        if (!FetchName<true>(cx, obj, holder, name, shape, vp))
-            return false;
-    } else {
-        if (!FetchName<false>(cx, obj, holder, name, shape, vp))
-            return false;
-    }
-
     // Monitor changes to cache entry.
     types::TypeScript::Monitor(cx, script, pc, vp);
 
     return true;
 }
 
 bool
 CallsiteCloneIC::attach(JSContext *cx, HandleScript outerScript, IonScript *ion,
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -974,17 +974,19 @@ class MAryInstruction : public MInstruct
     explicit MAryInstruction(const MAryInstruction<Arity> &other)
       : MInstruction(other)
     {
         for (int i = 0; i < (int) Arity; i++) // N.B. use |int| to avoid warnings when Arity == 0
             operands_[i].init(other.operands_[i].producer(), this);
     }
 };
 
-class MNullaryInstruction : public MAryInstruction<0>
+class MNullaryInstruction
+  : public MAryInstruction<0>,
+    public NoTypePolicy::Data
 { };
 
 class MUnaryInstruction : public MAryInstruction<1>
 {
   protected:
     explicit MUnaryInstruction(MDefinition *ins)
     {
         initOperand(0, ins);
@@ -1310,17 +1312,19 @@ class MConstant : public MNullaryInstruc
     void truncate();
 
     bool canProduceFloat32() const;
 
     ALLOW_CLONE(MConstant)
 };
 
 // Generic constructor of SIMD valuesX4.
-class MSimdValueX4 : public MQuaternaryInstruction
+class MSimdValueX4
+  : public MQuaternaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdValueX4(MIRType type, MDefinition *x, MDefinition *y, MDefinition *z, MDefinition *w)
       : MQuaternaryInstruction(x, y, z, w)
     {
         MOZ_ASSERT(IsSimdType(type));
         MOZ_ASSERT(SimdTypeToLength(type) == 4);
         mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
@@ -1355,17 +1359,19 @@ class MSimdValueX4 : public MQuaternaryI
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdValueX4)
 };
 
 // Generic constructor of SIMD valuesX4.
-class MSimdSplatX4 : public MUnaryInstruction
+class MSimdSplatX4
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdSplatX4(MIRType type, MDefinition *v)
       : MUnaryInstruction(v)
     {
         MOZ_ASSERT(IsSimdType(type));
         mozilla::DebugOnly<MIRType> scalarType = SimdTypeToScalarType(type);
         MOZ_ASSERT(scalarType == v->type());
@@ -1395,17 +1401,18 @@ class MSimdSplatX4 : public MUnaryInstru
     }
 
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdSplatX4)
 };
 
 // A constant SIMD value.
-class MSimdConstant : public MNullaryInstruction
+class MSimdConstant
+  : public MNullaryInstruction
 {
     SimdConstant value_;
 
   protected:
     MSimdConstant(const SimdConstant &v, MIRType type) : value_(v) {
         MOZ_ASSERT(IsSimdType(type));
         setResultType(type);
         setMovable();
@@ -1430,17 +1437,19 @@ class MSimdConstant : public MNullaryIns
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MSimdConstant)
 };
 
 // Converts all lanes of a given vector into the type of another vector
-class MSimdConvert : public MUnaryInstruction
+class MSimdConvert
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MSimdConvert(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
         MOZ_ASSERT(IsSimdType(toType));
         setResultType(toType);
     }
@@ -1458,17 +1467,19 @@ class MSimdConvert : public MUnaryInstru
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     ALLOW_CLONE(MSimdConvert)
 };
 
 // Casts bits of a vector input to another SIMD type (doesn't generate code).
-class MSimdReinterpretCast : public MUnaryInstruction
+class MSimdReinterpretCast
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MSimdReinterpretCast(MDefinition *obj, MIRType fromType, MIRType toType)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
         MOZ_ASSERT(IsSimdType(toType));
         setResultType(toType);
     }
@@ -1486,17 +1497,19 @@ class MSimdReinterpretCast : public MUna
     }
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     ALLOW_CLONE(MSimdReinterpretCast)
 };
 
 // Extracts a lane element from a given vector type, given by its lane symbol.
-class MSimdExtractElement : public MUnaryInstruction
+class MSimdExtractElement
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     SimdLane lane_;
 
     MSimdExtractElement(MDefinition *obj, MIRType type, SimdLane lane)
       : MUnaryInstruction(obj), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(obj->type()));
@@ -1528,17 +1541,19 @@ class MSimdExtractElement : public MUnar
         if (other->lane_ != lane_)
             return false;
         return congruentIfOperandsEqual(other);
     }
     ALLOW_CLONE(MSimdExtractElement)
 };
 
 // Replaces the datum in the given lane by a scalar value of the same type.
-class MSimdInsertElement : public MBinaryInstruction
+class MSimdInsertElement
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     SimdLane lane_;
 
     MSimdInsertElement(MDefinition *vec, MDefinition *val, MIRType type, SimdLane lane)
       : MBinaryInstruction(vec, val), lane_(lane)
     {
         MOZ_ASSERT(IsSimdType(type) && vec->type() == type);
@@ -1578,17 +1593,19 @@ class MSimdInsertElement : public MBinar
     bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins) && lane_ == ins->toSimdInsertElement()->lane();
     }
 
     ALLOW_CLONE(MSimdInsertElement)
 };
 
 // Extracts the sign bits from a given vector, returning an MIRType_Int32.
-class MSimdSignMask : public MUnaryInstruction
+class MSimdSignMask
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     explicit MSimdSignMask(MDefinition *obj)
       : MUnaryInstruction(obj)
     {
         MOZ_ASSERT(IsSimdType(obj->type()));
         setResultType(MIRType_Int32);
         setMovable();
@@ -1646,17 +1663,20 @@ class MSimdShuffleBase
     bool lanesMatch(uint32_t x, uint32_t y, uint32_t z, uint32_t w) const {
         return ((x << 0) | (y << 3) | (z << 6) | (w << 9)) == laneMask_;
     }
 };
 
 // Applies a shuffle operation to the input, putting the input lanes as
 // indicated in the output register's lanes. This implements the SIMD.js
 // "shuffle" function, that takes one vector and one mask.
-class MSimdSwizzle : public MUnaryInstruction, public MSimdShuffleBase
+class MSimdSwizzle
+  : public MUnaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
 {
   protected:
     MSimdSwizzle(MDefinition *obj, MIRType type,
                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
       : MUnaryInstruction(obj), MSimdShuffleBase(laneX, laneY, laneZ, laneW, type)
     {
         MOZ_ASSERT(laneX < 4 && laneY < 4 && laneZ < 4 && laneW < 4);
         MOZ_ASSERT(IsSimdType(obj->type()));
@@ -1689,17 +1709,20 @@ class MSimdSwizzle : public MUnaryInstru
     MDefinition *foldsTo(TempAllocator &alloc);
 
     ALLOW_CLONE(MSimdSwizzle)
 };
 
 // Applies a shuffle operation to the inputs, selecting the 2 first lanes of the
 // output from lanes of the first input, and the 2 last lanes of the output from
 // lanes of the second input.
-class MSimdShuffle : public MBinaryInstruction, public MSimdShuffleBase
+class MSimdShuffle
+  : public MBinaryInstruction,
+    public MSimdShuffleBase,
+    public NoTypePolicy::Data
 {
     MSimdShuffle(MDefinition *lhs, MDefinition *rhs, MIRType type,
                  uint32_t laneX, uint32_t laneY, uint32_t laneZ, uint32_t laneW)
       : MBinaryInstruction(lhs, rhs), MSimdShuffleBase(laneX, laneY, laneZ, laneW, lhs->type())
     {
         MOZ_ASSERT(laneX < 8 && laneY < 8 && laneZ < 8 && laneW < 8);
         MOZ_ASSERT(IsSimdType(lhs->type()));
         MOZ_ASSERT(IsSimdType(rhs->type()));
@@ -1745,17 +1768,19 @@ class MSimdShuffle : public MBinaryInstr
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MSimdShuffle)
 };
 
-class MSimdUnaryArith : public MUnaryInstruction
+class MSimdUnaryArith
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         abs,
         neg,
         not_,
         reciprocal,
         reciprocalSqrt,
@@ -1794,17 +1819,19 @@ class MSimdUnaryArith : public MUnaryIns
     }
 
     ALLOW_CLONE(MSimdUnaryArith);
 };
 
 // Compares each value of a SIMD vector to each corresponding lane's value of
 // another SIMD vector, and returns a int32x4 vector containing the results of
 // the comparison: all bits are set to 1 if the comparison is true, 0 otherwise.
-class MSimdBinaryComp : public MBinaryInstruction
+class MSimdBinaryComp
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         greaterThan,
         greaterThanOrEqual,
         lessThan,
         lessThanOrEqual,
         equal,
@@ -1873,17 +1900,19 @@ class MSimdBinaryComp : public MBinaryIn
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryComp()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryComp)
 };
 
-class MSimdBinaryArith : public MBinaryInstruction
+class MSimdBinaryArith
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         Add,
         Sub,
         Mul,
         Div,
         Min,
@@ -1940,17 +1969,19 @@ class MSimdBinaryArith : public MBinaryI
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryArith()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryArith)
 };
 
-class MSimdBinaryBitwise : public MBinaryInstruction
+class MSimdBinaryBitwise
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         and_,
         or_,
         xor_
     };
 
@@ -1986,17 +2017,19 @@ class MSimdBinaryBitwise : public MBinar
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdBinaryBitwise()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryBitwise)
 };
 
-class MSimdShift : public MBinaryInstruction
+class MSimdShift
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   public:
     enum Operation {
         lsh,
         rsh,
         ursh
     };
 
@@ -2029,17 +2062,19 @@ class MSimdShift : public MBinaryInstruc
         if (!binaryCongruentTo(ins))
             return false;
         return operation_ == ins->toSimdShift()->operation();
     }
 
     ALLOW_CLONE(MSimdShift)
 };
 
-class MSimdSelect : public MTernaryInstruction
+class MSimdSelect
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
 {
     bool isElementWise_;
 
     MSimdSelect(MDefinition *mask, MDefinition *lhs, MDefinition *rhs, MIRType type,
                 bool isElementWise)
       : MTernaryInstruction(mask, lhs, rhs), isElementWise_(isElementWise)
     {
         MOZ_ASSERT(IsSimdType(type));
@@ -2367,17 +2402,19 @@ class MAryControlInstruction : public MC
         return successors_[i];
     }
     void replaceSuccessor(size_t i, MBasicBlock *succ) MOZ_FINAL MOZ_OVERRIDE {
         successors_[i] = succ;
     }
 };
 
 // Jump to the start of another basic block.
-class MGoto : public MAryControlInstruction<0, 1>
+class MGoto
+  : public MAryControlInstruction<0, 1>,
+    public NoTypePolicy::Data
 {
     explicit MGoto(MBasicBlock *target) {
         setSuccessor(0, target);
     }
 
   public:
     INSTRUCTION_HEADER(Goto)
     static MGoto *New(TempAllocator &alloc, MBasicBlock *target);
@@ -2461,17 +2498,18 @@ class MTest
     }
 #endif
 };
 
 // Equivalent to MTest(true, successor, fake), except without the foldsTo
 // method. This allows IonBuilder to insert fake CFG edges to magically protect
 // control flow for try-catch blocks.
 class MGotoWithFake
-  : public MAryControlInstruction<0, 2>
+  : public MAryControlInstruction<0, 2>,
+    public NoTypePolicy::Data
 {
     MGotoWithFake(MBasicBlock *successor, MBasicBlock *fake)
     {
         setSuccessor(0, successor);
         setSuccessor(1, fake);
     }
 
   public:
@@ -2574,17 +2612,19 @@ class AlwaysTenured
 
 typedef AlwaysTenured<JSObject*> AlwaysTenuredObject;
 typedef AlwaysTenured<NativeObject*> AlwaysTenuredNativeObject;
 typedef AlwaysTenured<JSFunction*> AlwaysTenuredFunction;
 typedef AlwaysTenured<JSScript*> AlwaysTenuredScript;
 typedef AlwaysTenured<PropertyName*> AlwaysTenuredPropertyName;
 typedef AlwaysTenured<Shape*> AlwaysTenuredShape;
 
-class MNewArray : public MUnaryInstruction
+class MNewArray
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     // Number of space to allocate for the array.
     uint32_t count_;
 
     // Heap where the array should be allocated.
     gc::InitialHeap initialHeap_;
     // Allocate space at initialization or not
@@ -2729,17 +2769,19 @@ class MNewArrayDynamicLength
         return initialHeap_;
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MNewObject : public MUnaryInstruction
+class MNewObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     gc::InitialHeap initialHeap_;
     bool templateObjectIsClassPrototype_;
 
     MNewObject(types::CompilerConstraintList *constraints, MConstant *templateConst,
                gc::InitialHeap initialHeap, bool templateObjectIsClassPrototype)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap),
@@ -2790,17 +2832,19 @@ class MNewObject : public MUnaryInstruct
     bool canRecoverOnBailout() const {
         // The template object can safely be used in the recover instruction
         // because it can never be mutated by any other function execution.
         return true;
     }
 };
 
 // Could be allocating either a new array or a new object.
-class MNewPar : public MUnaryInstruction
+class MNewPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredNativeObject templateObject_;
 
     MNewPar(MDefinition *cx, NativeObject *templateObject)
       : MUnaryInstruction(cx),
         templateObject_(templateObject)
     {
         setResultType(MIRType_Object);
@@ -3499,31 +3543,35 @@ class MBail : public MNullaryInstruction
         return AliasSet::None();
     }
 
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
 };
 
-class MUnreachable : public MAryControlInstruction<0, 0>
+class MUnreachable
+  : public MAryControlInstruction<0, 0>,
+    public NoTypePolicy::Data
 {
   public:
     INSTRUCTION_HEADER(Unreachable)
 
     static MUnreachable *New(TempAllocator &alloc) {
         return new(alloc) MUnreachable();
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MAssertFloat32 : public MUnaryInstruction
+class MAssertFloat32
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   protected:
     bool mustBeFloat32_;
 
     MAssertFloat32(MDefinition *value, bool mustBeFloat32)
       : MUnaryInstruction(value), mustBeFloat32_(mustBeFloat32)
     {
     }
@@ -3821,17 +3869,19 @@ class MCompare
         if (!binaryCongruentTo(ins))
             return false;
         return compareType() == ins->toCompare()->compareType() &&
                jsop() == ins->toCompare()->jsop();
     }
 };
 
 // Takes a typed value and returns an untyped value.
-class MBox : public MUnaryInstruction
+class MBox
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MBox(TempAllocator &alloc, MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setResultType(MIRType_Value);
         if (ins->resultTypeSet()) {
             setResultTypeSet(ins->resultTypeSet());
         } else if (ins->type() != MIRType_Value) {
@@ -3977,17 +4027,19 @@ class MUnbox MOZ_FINAL : public MUnaryIn
         // Should only be called if we're already Infallible or TypeBarrier
         MOZ_ASSERT(mode() != Fallible);
         mode_ = Infallible;
     }
 
     ALLOW_CLONE(MUnbox)
 };
 
-class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy::Data
+class MGuardObject
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
 {
     explicit MGuardObject(MDefinition *ins)
       : MUnaryInstruction(ins)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Object);
     }
@@ -4023,17 +4075,18 @@ class MGuardString
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MAssertRange
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     // This is the range checked by the assertion. Don't confuse this with the
     // range_ member or the range() accessor. Since MAssertRange doesn't return
     // a value, it doesn't use those.
     const Range *assertedRange_;
 
     MAssertRange(MDefinition *ins, const Range *assertedRange)
       : MUnaryInstruction(ins), assertedRange_(assertedRange)
@@ -4059,17 +4112,18 @@ class MAssertRange
     }
 
     void printOpcode(FILE *fp) const;
 };
 
 // Caller-side allocation of |this| for |new|:
 // Given a templateobject, construct |this| for JSOP_NEW
 class MCreateThisWithTemplate
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     gc::InitialHeap initialHeap_;
 
     MCreateThisWithTemplate(types::CompilerConstraintList *constraints, MConstant *templateConst,
                             gc::InitialHeap initialHeap)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap)
     {
@@ -4470,17 +4524,18 @@ class MToFloat32
         return true;
     }
 
     ALLOW_CLONE(MToFloat32)
 };
 
 // Converts a uint32 to a double (coming from asm.js).
 class MAsmJSUnsignedToDouble
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSUnsignedToDouble(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Double);
         setMovable();
     }
 
@@ -4496,17 +4551,18 @@ class MAsmJSUnsignedToDouble
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Converts a uint32 to a float32 (coming from asm.js).
 class MAsmJSUnsignedToFloat32
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSUnsignedToFloat32(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Float32);
         setMovable();
     }
 
@@ -6015,17 +6071,18 @@ class MConcat
     bool canRecoverOnBailout() const {
         return true;
     }
 
     ALLOW_CLONE(MConcat)
 };
 
 class MConcatPar
-  : public MTernaryInstruction
+  : public MTernaryInstruction,
+    public NoTypePolicy::Data
 {
     MConcatPar(MDefinition *cx, MDefinition *left, MDefinition *right)
       : MTernaryInstruction(cx, left, right)
     {
         // Type analysis has already run, before replacing with the parallel
         // variant.
         MOZ_ASSERT(left->type() == MIRType_String && right->type() == MIRType_String);
 
@@ -6227,17 +6284,20 @@ class MLoadArrowThis
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
 
-class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
+class MPhi MOZ_FINAL
+  : public MDefinition,
+    public InlineListNode<MPhi>,
+    public NoTypePolicy::Data
 {
     js::Vector<MUse, 2, JitAllocPolicy> inputs_;
 
     TruncateKind truncateKind_;
     bool hasBackedgeType_;
     bool triedToSpecialize_;
     bool isIterator_;
     bool canProduceFloat32_;
@@ -6410,17 +6470,19 @@ class MPhi MOZ_FINAL : public MDefinitio
 
     TruncateKind operandTruncateKind(size_t index) const;
     bool needTruncation(TruncateKind kind);
     void truncate();
 };
 
 // The goal of a Beta node is to split a def at a conditionally taken
 // branch, so that uses dominated by it have a different name.
-class MBeta : public MUnaryInstruction
+class MBeta
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     // This is the range induced by a comparison and branch in a preceding
     // block. Note that this does not reflect any range constraints from
     // the input value itself, so this value may differ from the range()
     // range after it is computed.
     const Range *comparison_;
 
@@ -6444,17 +6506,19 @@ class MBeta : public MUnaryInstruction
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
 };
 
 // MIR representation of a Value on the OSR BaselineFrame.
 // The Value is indexed off of OsrFrameReg.
-class MOsrValue : public MUnaryInstruction
+class MOsrValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     ptrdiff_t frameOffset_;
 
     MOsrValue(MOsrEntry *entry, ptrdiff_t frameOffset)
       : MUnaryInstruction(entry),
         frameOffset_(frameOffset)
     {
@@ -6477,17 +6541,19 @@ class MOsrValue : public MUnaryInstructi
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // MIR representation of a JSObject scope chain pointer on the OSR BaselineFrame.
 // The pointer is indexed off of OsrFrameReg.
-class MOsrScopeChain : public MUnaryInstruction
+class MOsrScopeChain
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrScopeChain(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Object);
     }
 
@@ -6499,17 +6565,19 @@ class MOsrScopeChain : public MUnaryInst
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // MIR representation of a JSObject ArgumentsObject pointer on the OSR BaselineFrame.
 // The pointer is indexed off of OsrFrameReg.
-class MOsrArgumentsObject : public MUnaryInstruction
+class MOsrArgumentsObject
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrArgumentsObject(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Object);
     }
 
@@ -6521,17 +6589,19 @@ class MOsrArgumentsObject : public MUnar
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // MIR representation of the return value on the OSR BaselineFrame.
 // The Value is indexed off of OsrFrameReg.
-class MOsrReturnValue : public MUnaryInstruction
+class MOsrReturnValue
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     explicit MOsrReturnValue(MOsrEntry *entry)
       : MUnaryInstruction(entry)
     {
         setResultType(MIRType_Value);
     }
 
@@ -6542,29 +6612,32 @@ class MOsrReturnValue : public MUnaryIns
     }
 
     MOsrEntry *entry() {
         return getOperand(0)->toOsrEntry();
     }
 };
 
 // Check the current frame for over-recursion past the global stack limit.
-class MCheckOverRecursed : public MNullaryInstruction
+class MCheckOverRecursed
+  : public MNullaryInstruction
 {
   public:
     INSTRUCTION_HEADER(CheckOverRecursed)
 
     static MCheckOverRecursed *New(TempAllocator &alloc) {
         return new(alloc) MCheckOverRecursed();
     }
 };
 
 // Check the current frame for over-recursion past the global stack limit.
 // Uses the per-thread recursion limit.
-class MCheckOverRecursedPar : public MUnaryInstruction
+class MCheckOverRecursedPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MCheckOverRecursedPar(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_None);
         setGuard();
         setMovable();
     }
@@ -6577,17 +6650,19 @@ class MCheckOverRecursedPar : public MUn
     }
 
     MDefinition *forkJoinContext() const {
         return getOperand(0);
     }
 };
 
 // Check for an interrupt (or rendezvous) in parallel mode.
-class MInterruptCheckPar : public MUnaryInstruction
+class MInterruptCheckPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MInterruptCheckPar(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_None);
         setGuard();
     }
 
@@ -6622,17 +6697,18 @@ class MInterruptCheck : public MNullaryI
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Check whether we need to fire the interrupt handler at loop headers and
 // function prologues in asm.js. Generated only if we can't use implicit
 // interrupt checks with signal handlers.
-class MAsmJSInterruptCheck : public MNullaryInstruction
+class MAsmJSInterruptCheck
+  : public MNullaryInstruction
 {
     Label *interruptExit_;
     CallSiteDesc funcDesc_;
 
     MAsmJSInterruptCheck(Label *interruptExit, const CallSiteDesc &funcDesc)
       : interruptExit_(interruptExit), funcDesc_(funcDesc)
     {}
 
@@ -6697,17 +6773,19 @@ class MThrowUninitializedLexical : publi
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // If not defined, set a global variable to |undefined|.
-class MDefVar : public MUnaryInstruction
+class MDefVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredPropertyName name_; // Target name to be defined.
     unsigned attrs_; // Attributes to be set.
 
   private:
     MDefVar(PropertyName *name, unsigned attrs, MDefinition *scopeChain)
       : MUnaryInstruction(scopeChain),
         name_(name),
@@ -6733,17 +6811,19 @@ class MDefVar : public MUnaryInstruction
     MDefinition *scopeChain() const {
         return getOperand(0);
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
-class MDefFun : public MUnaryInstruction
+class MDefFun
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenuredFunction fun_;
 
   private:
     MDefFun(JSFunction *fun, MDefinition *scopeChain)
       : MUnaryInstruction(scopeChain),
         fun_(fun)
     {}
@@ -6972,17 +7052,17 @@ class MStringReplace
         if (pattern()->isRegExp())
             return !pattern()->toRegExp()->source()->global();
         return false;
     }
 };
 
 class MSubstr
   : public MTernaryInstruction,
-    public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>
+    public Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>::Data
 {
   private:
 
     MSubstr(MDefinition *string, MDefinition *begin, MDefinition *length)
       : MTernaryInstruction(string, begin, length)
     {
         setResultType(MIRType_String);
     }
@@ -7254,17 +7334,18 @@ class MConstantElements : public MNullar
         return AliasSet::None();
     }
 
     ALLOW_CLONE(MConstantElements)
 };
 
 // Passes through an object's elements, after ensuring it is entirely doubles.
 class MConvertElementsToDoubles
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MConvertElementsToDoubles(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setGuard();
         setMovable();
         setResultType(MIRType_Elements);
     }
@@ -7368,17 +7449,18 @@ class MMaybeCopyElementsForWrite
         return false;
     }
 #endif
 
 };
 
 // Load the initialized length from an elements header.
 class MInitializedLength
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MInitializedLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
@@ -7402,17 +7484,18 @@ class MInitializedLength
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MInitializedLength)
 };
 
 // Store to the initialized length in an elements header. Note the input is an
 // *index*, one less than the desired length.
 class MSetInitializedLength
-  : public MAryInstruction<2>
+  : public MAryInstruction<2>,
+    public NoTypePolicy::Data
 {
     MSetInitializedLength(MDefinition *elements, MDefinition *index) {
         initOperand(0, elements);
         initOperand(1, index);
     }
 
   public:
     INSTRUCTION_HEADER(SetInitializedLength)
@@ -7431,17 +7514,18 @@ class MSetInitializedLength
         return AliasSet::Store(AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MSetInitializedLength)
 };
 
 // Load the array length from an elements header.
 class MArrayLength
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MArrayLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setResultType(MIRType_Int32);
         setMovable();
     }
 
@@ -7465,17 +7549,18 @@ class MArrayLength
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MArrayLength)
 };
 
 // Store to the length in an elements header. Note the input is an *index*, one
 // less than the desired length.
 class MSetArrayLength
-  : public MAryInstruction<2>
+  : public MAryInstruction<2>,
+    public NoTypePolicy::Data
 {
     MSetArrayLength(MDefinition *elements, MDefinition *index) {
         initOperand(0, elements);
         initOperand(1, index);
     }
 
   public:
     INSTRUCTION_HEADER(SetArrayLength)
@@ -7601,17 +7686,18 @@ class MTypedObjectElements
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
 class MSetTypedObjectOffset
-  : public MBinaryInstruction
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
   private:
     MSetTypedObjectOffset(MDefinition *object, MDefinition *offset)
       : MBinaryInstruction(object, offset)
     {
         MOZ_ASSERT(object->type() == MIRType_Object);
         MOZ_ASSERT(offset->type() == MIRType_Int32);
         setResultType(MIRType_None);
@@ -7704,17 +7790,18 @@ class MNot
         return true;
     }
 };
 
 // Bailout if index + minimum < 0 or index + maximum >= length. The length used
 // in a bounds check must not be negative, or the wrong result may be computed
 // (unsigned comparisons may be used).
 class MBoundsCheck
-  : public MBinaryInstruction
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     // Range over which to perform the bounds check, may be modified by GVN.
     int32_t minimum_;
     int32_t maximum_;
 
     MBoundsCheck(MDefinition *index, MDefinition *length)
       : MBinaryInstruction(index, length), minimum_(0), maximum_(0)
     {
@@ -7765,17 +7852,18 @@ class MBoundsCheck
     }
     void computeRange(TempAllocator &alloc);
 
     ALLOW_CLONE(MBoundsCheck)
 };
 
 // Bailout if index < minimum.
 class MBoundsCheckLower
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     int32_t minimum_;
     bool fallible_;
 
     explicit MBoundsCheckLower(MDefinition *index)
       : MUnaryInstruction(index), minimum_(0), fallible_(true)
     {
         setGuard();
@@ -8899,17 +8987,19 @@ class MStoreTypedArrayElementStatic :
     bool canConsumeFloat32(MUse *use) const {
         return use == getUseFor(1) && viewType() == Scalar::Float32;
     }
     void collectRangeInfoPreTrunc();
 };
 
 // Compute an "effective address", i.e., a compound computation of the form:
 //   base + index * scale + displacement
-class MEffectiveAddress : public MBinaryInstruction
+class MEffectiveAddress
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     MEffectiveAddress(MDefinition *base, MDefinition *index, Scale scale, int32_t displacement)
       : MBinaryInstruction(base, index), scale_(scale), displacement_(displacement)
     {
         MOZ_ASSERT(base->type() == MIRType_Int32);
         MOZ_ASSERT(index->type() == MIRType_Int32);
         setMovable();
         setResultType(MIRType_Int32);
@@ -9939,17 +10029,18 @@ class MForkJoinContext
     bool possiblyCalls() const {
         return true;
     }
 };
 
 // Calls the ForkJoinGetSlice stub, used for inlining the eponymous intrinsic.
 // Only applicable in ParallelExecution.
 class MForkJoinGetSlice
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MForkJoinGetSlice(MDefinition *cx)
       : MUnaryInstruction(cx)
     {
         setResultType(MIRType_Int32);
     }
 
   public:
@@ -10886,17 +10977,18 @@ class MIteratorMore
     }
 
     MDefinition *iterator() const {
         return getOperand(0);
     }
 };
 
 class MIsNoIter
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     explicit MIsNoIter(MDefinition *def)
       : MUnaryInstruction(def)
     {
         setResultType(MIRType_Boolean);
         setMovable();
     }
 
@@ -11392,17 +11484,19 @@ class MTypeBarrier
     }
 
     ALLOW_CLONE(MTypeBarrier)
 };
 
 // Like MTypeBarrier, guard that the value is in the given type set. This is
 // used before property writes to ensure the value being written is represented
 // in the property types for the object.
-class MMonitorTypes : public MUnaryInstruction, public BoxInputsPolicy::Data
+class MMonitorTypes
+  : public MUnaryInstruction,
+    public BoxInputsPolicy::Data
 {
     const types::TemporaryTypeSet *typeSet_;
     BarrierKind barrierKind_;
 
     MMonitorTypes(MDefinition *def, const types::TemporaryTypeSet *types, BarrierKind kind)
       : MUnaryInstruction(def),
         typeSet_(types),
         barrierKind_(kind)
@@ -11547,17 +11641,19 @@ class MNewRunOnceCallObject : public MNe
 
     static MNewRunOnceCallObject *
     New(TempAllocator &alloc, CallObject *templateObj)
     {
         return new(alloc) MNewRunOnceCallObject(templateObj);
     }
 };
 
-class MNewCallObjectPar : public MUnaryInstruction
+class MNewCallObjectPar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenured<CallObject*> templateObj_;
 
     MNewCallObjectPar(MDefinition *cx, CallObject *templateObj)
         : MUnaryInstruction(cx),
           templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
@@ -11666,17 +11762,19 @@ class MEnclosingScope : public MLoadFixe
         // ScopeObject reserved slots are immutable.
         return AliasSet::None();
     }
 };
 
 // Creates a dense array of the given length.
 //
 // Note: the template object should be an *empty* dense array!
-class MNewDenseArrayPar : public MBinaryInstruction
+class MNewDenseArrayPar
+  : public MBinaryInstruction,
+    public NoTypePolicy::Data
 {
     AlwaysTenured<ArrayObject*> templateObject_;
 
     MNewDenseArrayPar(MDefinition *cx, MDefinition *length, ArrayObject *templateObject)
       : MBinaryInstruction(cx, length),
         templateObject_(templateObject)
     {
         MOZ_ASSERT(length->type() == MIRType_Int32);
@@ -12077,17 +12175,17 @@ class MMemoryBarrier
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
 };
 
 class MCompareExchangeTypedArrayElement
   : public MAryInstruction<4>,
-    public MixPolicy< MixPolicy<ObjectPolicy<0>, IntPolicy<1> >, MixPolicy<IntPolicy<2>, IntPolicy<3> > >
+    public Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>::Data
 {
     Scalar::Type arrayType_;
 
     explicit MCompareExchangeTypedArrayElement(MDefinition *elements, MDefinition *index,
                                                Scalar::Type arrayType, MDefinition *oldval,
                                                MDefinition *newval)
       : arrayType_(arrayType)
     {
@@ -12132,17 +12230,17 @@ class MCompareExchangeTypedArrayElement
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::TypedArrayElement);
     }
 };
 
 class MAtomicTypedArrayElementBinop
     : public MAryInstruction<3>,
-      public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >
+      public Mix3Policy< ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
 {
   private:
     AtomicOp op_;
     Scalar::Type arrayType_;
 
   protected:
     explicit MAtomicTypedArrayElementBinop(AtomicOp op, MDefinition *elements, MDefinition *index,
                                            Scalar::Type arrayType, MDefinition *value)
@@ -12195,17 +12293,19 @@ class MDebugger : public MNullaryInstruc
   public:
     INSTRUCTION_HEADER(Debugger);
 
     static MDebugger *New(TempAllocator &alloc) {
         return new(alloc) MDebugger();
     }
 };
 
-class MAsmJSNeg : public MUnaryInstruction
+class MAsmJSNeg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSNeg(MDefinition *op, MIRType type)
       : MUnaryInstruction(op)
     {
         setResultType(type);
         setMovable();
     }
 
@@ -12226,17 +12326,20 @@ class MAsmJSHeapAccess
       : viewType_(vt), needsBoundsCheck_(needsBoundsCheck)
     {}
 
     Scalar::Type viewType() const { return viewType_; }
     bool needsBoundsCheck() const { return needsBoundsCheck_; }
     void removeBoundsCheck() { needsBoundsCheck_ = false; }
 };
 
-class MAsmJSLoadHeap : public MUnaryInstruction, public MAsmJSHeapAccess
+class MAsmJSLoadHeap
+  : public MUnaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MemoryBarrierBits barrierBefore_;
     MemoryBarrierBits barrierAfter_;
 
     MAsmJSLoadHeap(Scalar::Type vt, MDefinition *ptr, bool needsBoundsCheck,
                    MemoryBarrierBits before, MemoryBarrierBits after)
       : MUnaryInstruction(ptr),
         MAsmJSHeapAccess(vt, needsBoundsCheck),
@@ -12292,17 +12395,20 @@ class MAsmJSLoadHeap : public MUnaryInst
 
     bool congruentTo(const MDefinition *ins) const;
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
     bool mightAlias(const MDefinition *def) const;
 };
 
-class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
+class MAsmJSStoreHeap
+  : public MBinaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MemoryBarrierBits barrierBefore_;
     MemoryBarrierBits barrierAfter_;
 
     MAsmJSStoreHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *v, bool needsBoundsCheck,
                     MemoryBarrierBits before, MemoryBarrierBits after)
       : MBinaryInstruction(ptr, v),
         MAsmJSHeapAccess(vt, needsBoundsCheck),
@@ -12330,17 +12436,20 @@ class MAsmJSStoreHeap : public MBinaryIn
     MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
     MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSHeap);
     }
 };
 
-class MAsmJSCompareExchangeHeap : public MTernaryInstruction, public MAsmJSHeapAccess
+class MAsmJSCompareExchangeHeap
+  : public MTernaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     MAsmJSCompareExchangeHeap(Scalar::Type vt, MDefinition *ptr, MDefinition *oldv, MDefinition *newv,
                               bool needsBoundsCheck)
         : MTernaryInstruction(ptr, oldv, newv),
           MAsmJSHeapAccess(vt, needsBoundsCheck)
     {
         setGuard();             // Not removable
         setResultType(MIRType_Int32);
@@ -12360,17 +12469,20 @@ class MAsmJSCompareExchangeHeap : public
     MDefinition *oldValue() const { return getOperand(1); }
     MDefinition *newValue() const { return getOperand(2); }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSHeap);
     }
 };
 
-class MAsmJSAtomicBinopHeap : public MBinaryInstruction, public MAsmJSHeapAccess
+class MAsmJSAtomicBinopHeap
+  : public MBinaryInstruction,
+    public MAsmJSHeapAccess,
+    public NoTypePolicy::Data
 {
     AtomicOp op_;
 
     MAsmJSAtomicBinopHeap(AtomicOp op, Scalar::Type vt, MDefinition *ptr, MDefinition *v,
                           bool needsBoundsCheck)
         : MBinaryInstruction(ptr, v),
           MAsmJSHeapAccess(vt, needsBoundsCheck),
           op_(op)
@@ -12427,17 +12539,19 @@ class MAsmJSLoadGlobalVar : public MNull
 
     AliasSet getAliasSet() const {
         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
     }
 
     bool mightAlias(const MDefinition *def) const;
 };
 
-class MAsmJSStoreGlobalVar : public MUnaryInstruction
+class MAsmJSStoreGlobalVar
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v)
       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
     {}
 
     unsigned globalDataOffset_;
 
   public:
@@ -12450,17 +12564,19 @@ class MAsmJSStoreGlobalVar : public MUna
     unsigned globalDataOffset() const { return globalDataOffset_; }
     MDefinition *value() const { return getOperand(0); }
 
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::AsmJSGlobalVar);
     }
 };
 
-class MAsmJSLoadFuncPtr : public MUnaryInstruction
+class MAsmJSLoadFuncPtr
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSLoadFuncPtr(unsigned globalDataOffset, MDefinition *index)
       : MUnaryInstruction(index), globalDataOffset_(globalDataOffset)
     {
         setResultType(MIRType_Pointer);
     }
 
     unsigned globalDataOffset_;
@@ -12520,39 +12636,45 @@ class MAsmJSParameter : public MNullaryI
 
     static MAsmJSParameter *New(TempAllocator &alloc, ABIArg abi, MIRType mirType) {
         return new(alloc) MAsmJSParameter(abi, mirType);
     }
 
     ABIArg abi() const { return abi_; }
 };
 
-class MAsmJSReturn : public MAryControlInstruction<1, 0>
+class MAsmJSReturn
+  : public MAryControlInstruction<1, 0>,
+    public NoTypePolicy::Data
 {
     explicit MAsmJSReturn(MDefinition *ins) {
         initOperand(0, ins);
     }
 
   public:
     INSTRUCTION_HEADER(AsmJSReturn);
     static MAsmJSReturn *New(TempAllocator &alloc, MDefinition *ins) {
         return new(alloc) MAsmJSReturn(ins);
     }
 };
 
-class MAsmJSVoidReturn : public MAryControlInstruction<0, 0>
+class MAsmJSVoidReturn
+  : public MAryControlInstruction<0, 0>,
+    public NoTypePolicy::Data
 {
   public:
     INSTRUCTION_HEADER(AsmJSVoidReturn);
     static MAsmJSVoidReturn *New(TempAllocator &alloc) {
         return new(alloc) MAsmJSVoidReturn();
     }
 };
 
-class MAsmJSPassStackArg : public MUnaryInstruction
+class MAsmJSPassStackArg
+  : public MUnaryInstruction,
+    public NoTypePolicy::Data
 {
     MAsmJSPassStackArg(uint32_t spOffset, MDefinition *ins)
       : MUnaryInstruction(ins),
         spOffset_(spOffset)
     {}
 
     uint32_t spOffset_;
 
@@ -12567,17 +12689,19 @@ class MAsmJSPassStackArg : public MUnary
     void incrementOffset(uint32_t inc) {
         spOffset_ += inc;
     }
     MDefinition *arg() const {
         return getOperand(0);
     }
 };
 
-class MAsmJSCall MOZ_FINAL : public MVariadicInstruction
+class MAsmJSCall MOZ_FINAL
+  : public MVariadicInstruction,
+    public NoTypePolicy::Data
 {
   public:
     class Callee {
       public:
         enum Which { Internal, Dynamic, Builtin };
       private:
         Which which_;
         union {
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -22,56 +22,56 @@ EnsureOperandNotFloat32(TempAllocator &a
     if (in->type() == MIRType_Float32) {
         MToDouble *replace = MToDouble::New(alloc, in);
         def->block()->insertBefore(def, replace);
         def->replaceOperand(op, replace);
     }
 }
 
 MDefinition *
-BoxInputsPolicy::boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
-{
-    if (operand->isUnbox())
-        return operand->toUnbox()->input();
-    return alwaysBoxAt(alloc, at, operand);
-}
-
-MDefinition *
-BoxInputsPolicy::alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
+js::jit::AlwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
 {
     MDefinition *boxedOperand = operand;
     // Replace Float32 by double
     if (operand->type() == MIRType_Float32) {
         MInstruction *replace = MToDouble::New(alloc, operand);
         at->block()->insertBefore(at, replace);
         boxedOperand = replace;
     }
     MBox *box = MBox::New(alloc, boxedOperand);
     at->block()->insertBefore(at, box);
     return box;
 }
 
+static MDefinition *
+BoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
+{
+    if (operand->isUnbox())
+        return operand->toUnbox()->input();
+    return AlwaysBoxAt(alloc, at, operand);
+}
+
 bool
-BoxInputsPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
+BoxInputsPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Value)
             continue;
-        ins->replaceOperand(i, boxAt(alloc, ins, in));
+        ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
 ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType_None)
-        return BoxInputsPolicy::adjustInputs(alloc, ins);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32);
 
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == ins->type())
             continue;
 
@@ -109,17 +109,17 @@ ComparePolicy::adjustInputs(TempAllocato
             def->replaceOperand(i, replace);
         }
     }
 
     // Box inputs to get value
     if (compare->compareType() == MCompare::Compare_Unknown ||
         compare->compareType() == MCompare::Compare_Value)
     {
-        return BoxInputsPolicy::adjustInputs(alloc, def);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, def);
     }
 
     // Compare_Boolean specialization is done for "Anything === Bool"
     // If the LHS is boolean, we set the specialization to Compare_Int32.
     // This matches other comparisons of the form bool === bool and
     // generated code of Compare_Int32 is more efficient.
     if (compare->compareType() == MCompare::Compare_Boolean &&
         def->getOperand(0)->type() == MIRType_Boolean)
@@ -250,24 +250,24 @@ TypeBarrierPolicy::adjustInputs(TempAllo
     if (inputType == outputType)
         return true;
 
     // Output is a value, currently box the input.
     if (outputType == MIRType_Value) {
         // XXX: Possible optimization: decrease resultTypeSet to only include
         // the inputType. This will remove the need for boxing.
         MOZ_ASSERT(inputType != MIRType_Value);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // Box input if needed.
     if (inputType != MIRType_Value) {
         MOZ_ASSERT(ins->alwaysBails());
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
     }
 
     // We can't unbox a value to null/undefined/lazyargs. So keep output
     // also a value.
     // Note: Using setResultType shouldn't be done in TypePolicies,
     //       Here it is fine, since the type barrier has no uses.
     if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
         MOZ_ASSERT(!ins->hasDefUses());
@@ -314,28 +314,28 @@ TestPolicy::adjustInputs(TempAllocator &
       {
         MStringLength *length = MStringLength::New(alloc, op);
         ins->block()->insertBefore(ins, length);
         ins->replaceOperand(0, length);
         break;
       }
 
       default:
-        ins->replaceOperand(0, boxAt(alloc, ins, op));
+        ins->replaceOperand(0, BoxAt(alloc, ins, op));
         break;
     }
     return true;
 }
 
 bool
 BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MIRType specialization = ins->typePolicySpecialization();
     if (specialization == MIRType_None)
-        return BoxInputsPolicy::adjustInputs(alloc, ins);
+        return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
 
     MOZ_ASSERT(ins->type() == specialization);
     MOZ_ASSERT(specialization == MIRType_Int32 || specialization == MIRType_Double);
 
     // This policy works for both unary and binary bitwise operations.
     for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Int32)
@@ -523,17 +523,17 @@ template bool NoFloatPolicyAfter<2>::adj
 template <unsigned Op>
 bool
 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MDefinition *in = ins->getOperand(Op);
     if (in->type() == MIRType_Value)
         return true;
 
-    ins->replaceOperand(Op, boxAt(alloc, ins, in));
+    ins->replaceOperand(Op, BoxAt(alloc, ins, in));
     return true;
 }
 
 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 
 template <unsigned Op, MIRType Type>
@@ -589,17 +589,17 @@ ToDoublePolicy::staticAdjustInputs(TempA
       case MIRType_String:
       case MIRType_Symbol:
         // Objects might be effectful. Symbols give TypeError.
         break;
       default:
         break;
     }
 
-    in = boxAt(alloc, ins, in);
+    in = BoxAt(alloc, ins, in);
     ins->replaceOperand(0, in);
     return true;
 }
 
 bool
 ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MOZ_ASSERT(ins->isToInt32() || ins->isTruncateToInt32());
@@ -637,29 +637,29 @@ ToInt32Policy::staticAdjustInputs(TempAl
       case MIRType_String:
       case MIRType_Symbol:
         // Objects might be effectful. Symbols give TypeError.
         break;
       default:
         break;
     }
 
-    in = boxAt(alloc, ins, in);
+    in = BoxAt(alloc, ins, in);
     ins->replaceOperand(0, in);
     return true;
 }
 
 bool
 ToStringPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MOZ_ASSERT(ins->isToString());
 
     MIRType type = ins->getOperand(0)->type();
     if (type == MIRType_Object || type == MIRType_Symbol) {
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // TODO remove the following line once 966957 has landed
     EnsureOperandNotFloat32(alloc, ins, 0);
 
     return true;
 }
@@ -707,24 +707,24 @@ CallPolicy::adjustInputs(TempAllocator &
 
     return true;
 }
 
 bool
 CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     // The first operand should be an object.
-    SingleObjectPolicy::adjustInputs(alloc, ins);
+    SingleObjectPolicy::staticAdjustInputs(alloc, ins);
 
     // Box the index and value operands.
     for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
         MDefinition *in = ins->getOperand(i);
         if (in->type() == MIRType_Value)
             continue;
-        ins->replaceOperand(i, boxAt(alloc, ins, in));
+        ins->replaceOperand(i, BoxAt(alloc, ins, in));
     }
     return true;
 }
 
 bool
 InstanceOfPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
 {
     // Box first operand if it isn't object
@@ -756,17 +756,17 @@ StoreTypedArrayPolicy::adjustValueInput(
       case MIRType_Undefined:
         value->setImplicitlyUsedUnchecked();
         value = MConstant::New(alloc, DoubleNaNValue());
         ins->block()->insertBefore(ins, value->toInstruction());
         break;
       case MIRType_Object:
       case MIRType_String:
       case MIRType_Symbol:
-        value = boxAt(alloc, ins, value);
+        value = BoxAt(alloc, ins, value);
         break;
       default:
         MOZ_CRASH("Unexpected type");
     }
 
     if (value != curValue) {
         ins->replaceOperand(valueOperand, value);
         curValue = value;
@@ -831,26 +831,26 @@ StoreTypedArrayPolicy::adjustInputs(Temp
 bool
 StoreTypedArrayHolePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MStoreTypedArrayElementHole *store = ins->toStoreTypedArrayElementHole();
     MOZ_ASSERT(store->elements()->type() == MIRType_Elements);
     MOZ_ASSERT(store->index()->type() == MIRType_Int32);
     MOZ_ASSERT(store->length()->type() == MIRType_Int32);
 
-    return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
+    return StoreTypedArrayPolicy::adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
 }
 
 bool
 StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic();
 
     return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
-        adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
+        StoreTypedArrayPolicy::adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
 }
 
 bool
 StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     SingleObjectPolicy::staticAdjustInputs(alloc, ins);
 
     // Change the value input to a ToObjectOrNull instruction if it might be
@@ -889,17 +889,17 @@ ClampPolicy::adjustInputs(TempAllocator 
     MDefinition *in = ins->toClampToUint8()->input();
 
     switch (in->type()) {
       case MIRType_Int32:
       case MIRType_Double:
       case MIRType_Value:
         break;
       default:
-          ins->replaceOperand(0, boxAt(alloc, ins, in));
+          ins->replaceOperand(0, BoxAt(alloc, ins, in));
         break;
     }
 
     return true;
 }
 
 bool
 FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
@@ -910,29 +910,29 @@ FilterTypeSetPolicy::adjustInputs(TempAl
 
     // Input and output type are already in accordance.
     if (inputType == outputType)
         return true;
 
     // Output is a value, box the input.
     if (outputType == MIRType_Value) {
         MOZ_ASSERT(inputType != MIRType_Value);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
         return true;
     }
 
     // The outputType should be a subset of the inputType else we are in code
     // that has never executed yet. Bail to see the new type (if that hasn't
     // happened yet).
     if (inputType != MIRType_Value) {
         MBail *bail = MBail::New(alloc);
         ins->block()->insertBefore(ins, bail);
         bail->setDependency(ins->dependency());
         ins->setDependency(bail);
-        ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
+        ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
     }
 
     // We can't unbox a value to null/undefined/lazyargs. So keep output
     // also a value.
     // Note: Using setResultType shouldn't be done in TypePolicies,
     //       Here it is fine, since the type barrier has no uses.
     if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
         MOZ_ASSERT(!ins->hasDefUses());
@@ -988,18 +988,20 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(IntPolicy<0>)                                                     \
     _(IntPolicy<1>)                                                     \
     _(Mix3Policy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType_String>, BoxPolicy<2> >) \
     _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >)      \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, BoxPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >)         \
     _(Mix3Policy<ObjectPolicy<0>, ObjectPolicy<1>, IntPolicy<2> >)      \
+    _(Mix3Policy<StringPolicy<0>, IntPolicy<1>, IntPolicy<2>>)          \
     _(Mix3Policy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2> >)   \
     _(Mix3Policy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2> >)   \
+    _(Mix4Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2>, IntPolicy<3>>) \
     _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1> >)                        \
     _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1> >)   \
     _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1> >)            \
     _(MixPolicy<DoublePolicy<0>, DoublePolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1> >)            \
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
@@ -1041,49 +1043,48 @@ namespace jit {
     TEMPLATE_TYPE_POLICY_LIST(template<> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
 
 }
 }
 
 namespace {
 
-// Default function visited by the C++ lookup rules, if the MIR Instruction does
-// not inherit from a TypePolicy::Data type.
-static TypePolicy *
-thisTypePolicy() {
-    return nullptr;
-}
+// For extra-good measure in case an unqualified use is ever introduced.  (The
+// main use in the macro below is explicitly qualified so as not to consult
+// this scope and find this function.)
+inline TypePolicy *
+thisTypePolicy() MOZ_DELETE;
 
 static MIRType
-thisTypeSpecialization() {
+thisTypeSpecialization()
+{
     MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
 }
 
 }
 
 TypePolicy *
 MGetElementCache::thisTypePolicy()
 {
     if (type() == MIRType_Value)
         return PolicyV.thisTypePolicy();
     return PolicyT.thisTypePolicy();
 }
 
 // For each MIR Instruction, this macro define the |typePolicy| method which is
-// using the |thisTypePolicy| function.  We use the C++ lookup rules to select
-// the right |thisTypePolicy| member.  The |thisTypePolicy| function can either
-// be a member of the MIR Instruction, such as done for MGetElementCache, or a
-// member inherited from the TypePolicy::Data structure, or at last the global
-// with the same name if the instruction has no TypePolicy.
+// using the |thisTypePolicy| method.  The |thisTypePolicy| method is either a
+// member of the MIR Instruction, such as with MGetElementCache, a member
+// inherited from the TypePolicy::Data structure, or a member inherited from
+// NoTypePolicy if the MIR instruction has no type policy.
 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op)      \
     TypePolicy *                                \
     js::jit::M##op::typePolicy()                \
     {                                           \
-        return thisTypePolicy();                \
+        return M##op::thisTypePolicy();         \
     }                                           \
                                                 \
     MIRType                                     \
     js::jit::M##op::typePolicySpecialization()  \
     {                                           \
         return thisTypeSpecialization();        \
     }
 
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -11,16 +11,19 @@
 #include "jit/JitAllocPolicy.h"
 
 namespace js {
 namespace jit {
 
 class MInstruction;
 class MDefinition;
 
+extern MDefinition *
+AlwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
+
 // A type policy directs the type analysis phases, which insert conversion,
 // boxing, unboxing, and type changes as necessary.
 class TypePolicy
 {
   public:
     // Analyze the inputs of the instruction and perform one of the following
     // actions for each input:
     //  * Nothing; the input already type-checks.
@@ -57,154 +60,164 @@ struct TypeSpecializationData
 #define INHERIT_DATA_(DATA_TYPE)                        \
     struct Data : public DATA_TYPE                      \
     {                                                   \
         static TypePolicy *thisTypePolicy();            \
     }
 
 #define SPECIALIZATION_DATA_ INHERIT_DATA_(TypeSpecializationData)
 
-class BoxInputsPolicy : public TypePolicy
+class NoTypePolicy
 {
-  protected:
-    static MDefinition *boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
-
   public:
-    EMPTY_DATA_;
-    static MDefinition *alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand);
-    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    struct Data
+    {
+        static TypePolicy *thisTypePolicy() {
+            return nullptr;
+        }
+    };
 };
 
-class ArithPolicy : public BoxInputsPolicy
+class BoxInputsPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
+        return staticAdjustInputs(alloc, def);
+    }
 };
 
-class BitwisePolicy : public BoxInputsPolicy
+class ArithPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
-class ComparePolicy : public BoxInputsPolicy
+class BitwisePolicy MOZ_FINAL : public TypePolicy
+{
+  public:
+    SPECIALIZATION_DATA_;
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
+};
+
+class ComparePolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 // Policy for MTest instructions.
-class TestPolicy : public BoxInputsPolicy
+class TestPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class TypeBarrierPolicy : public BoxInputsPolicy
+class TypeBarrierPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class CallPolicy : public BoxInputsPolicy
+class CallPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 // Policy for MPow. First operand Double; second Double or Int32.
-class PowPolicy : public BoxInputsPolicy
+class PowPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     SPECIALIZATION_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
 // Expect a string for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class StringPolicy : public BoxInputsPolicy
+class StringPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a string for operand Op. Else a ToString instruction is inserted.
 template <unsigned Op>
-class ConvertToStringPolicy : public TypePolicy
+class ConvertToStringPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class IntPolicy : public BoxInputsPolicy
+class IntPolicy MOZ_FINAL : private TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect an Int for operand Op. Else a ToInt32 instruction is inserted.
 template <unsigned Op>
-class ConvertToInt32Policy : public BoxInputsPolicy
+class ConvertToInt32Policy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a double for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class DoublePolicy : public BoxInputsPolicy
+class DoublePolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 for operand Op. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class Float32Policy : public BoxInputsPolicy
+class Float32Policy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Expect a float32 OR a double for operand Op, but will prioritize Float32
 // if the result type is set as such. If the input is a Value, it is unboxed.
 template <unsigned Op>
-class FloatingPointPolicy : public TypePolicy
+class FloatingPointPolicy MOZ_FINAL : public TypePolicy
 {
 
   public:
     struct PolicyTypeData
     {
         MIRType policyType_;
 
         void setPolicyType(MIRType type) {
@@ -214,201 +227,224 @@ class FloatingPointPolicy : public TypeP
       protected:
         MIRType &thisTypeSpecialization() {
             return policyType_;
         }
     };
 
     INHERIT_DATA_(PolicyTypeData);
 
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 template <unsigned Op>
-class NoFloatPolicy : public TypePolicy
+class NoFloatPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Policy for guarding variadic instructions such as object / array state
 // instructions.
 template <unsigned FirstOp>
-class NoFloatPolicyAfter : public TypePolicy
+class NoFloatPolicyAfter MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
 // Box objects or strings as an input to a ToDouble instruction.
-class ToDoublePolicy : public BoxInputsPolicy
+class ToDoublePolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects, strings and undefined as input to a ToInt32 instruction.
-class ToInt32Policy : public BoxInputsPolicy
+class ToInt32Policy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 // Box objects as input to a ToString instruction.
-class ToStringPolicy : public BoxInputsPolicy
+class ToStringPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
 template <unsigned Op>
-class ObjectPolicy : public BoxInputsPolicy
+class ObjectPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Single-object input. If the input is a Value, it is unboxed. If it is
 // a primitive, we use ValueToNonNullObject.
 typedef ObjectPolicy<0> SingleObjectPolicy;
 
 template <unsigned Op>
-class BoxPolicy : public BoxInputsPolicy
+class BoxPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Boxes everything except inputs of type Type.
 template <unsigned Op, MIRType Type>
-class BoxExceptPolicy : public TypePolicy
+class BoxExceptPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Combine multiple policies.
 template <class Lhs, class Rhs>
-class MixPolicy : public TypePolicy
+class MixPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return Lhs::staticAdjustInputs(alloc, ins) && Rhs::staticAdjustInputs(alloc, ins);
     }
-    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
 // Combine three policies.
 template <class Policy1, class Policy2, class Policy3>
-class Mix3Policy : public TypePolicy
+class Mix3Policy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) {
         return Policy1::staticAdjustInputs(alloc, ins) &&
                Policy2::staticAdjustInputs(alloc, ins) &&
                Policy3::staticAdjustInputs(alloc, ins);
     }
-    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) {
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);
     }
 };
 
-class CallSetElementPolicy : public SingleObjectPolicy
+// Combine four policies.  (Missing variadic templates yet?)
+template <class Policy1, class Policy2, class Policy3, class Policy4>
+class Mix4Policy : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) {
+        return Policy1::staticAdjustInputs(alloc, ins) &&
+               Policy2::staticAdjustInputs(alloc, ins) &&
+               Policy3::staticAdjustInputs(alloc, ins) &&
+               Policy4::staticAdjustInputs(alloc, ins);
+    }
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
+        return staticAdjustInputs(alloc, ins);
+    }
+};
+
+class CallSetElementPolicy MOZ_FINAL : public TypePolicy
+{
+  public:
+    EMPTY_DATA_;
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 // First operand will be boxed to a Value (except for an object)
 // Second operand (if specified) will forcefully be unboxed to an object
-class InstanceOfPolicy : public TypePolicy
+class InstanceOfPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
-class StoreTypedArrayPolicy : public BoxInputsPolicy
+class StoreTypedArrayHolePolicy;
+class StoreTypedArrayElementStaticPolicy;
+
+class StoreTypedArrayPolicy : public TypePolicy
 {
-  protected:
-    bool adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType, MDefinition *value, int valueOperand);
+  private:
+    static bool adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType, MDefinition *value, int valueOperand);
+
+    friend class StoreTypedArrayHolePolicy;
+    friend class StoreTypedArrayElementStaticPolicy;
 
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class StoreTypedArrayHolePolicy : public StoreTypedArrayPolicy
+class StoreTypedArrayHolePolicy MOZ_FINAL : public StoreTypedArrayPolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class StoreTypedArrayElementStaticPolicy : public StoreTypedArrayPolicy
+class StoreTypedArrayElementStaticPolicy MOZ_FINAL : public StoreTypedArrayPolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class StoreUnboxedObjectOrNullPolicy : public TypePolicy
+class StoreUnboxedObjectOrNullPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
 };
 
 // Accepts integers and doubles. Everything else is boxed.
-class ClampPolicy : public BoxInputsPolicy
+class ClampPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
-class FilterTypeSetPolicy : public BoxInputsPolicy
+class FilterTypeSetPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
-    bool adjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
 };
 
 static inline bool
 CoercesToDouble(MIRType type)
 {
     if (type == MIRType_Undefined || IsFloatingPointType(type))
         return true;
     return false;
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -2122,20 +2122,21 @@ CodeGeneratorARM::visitAsmJSLoadGlobalVa
 
 void
 CodeGeneratorARM::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins)
 {
     const MAsmJSStoreGlobalVar *mir = ins->mir();
 
     MIRType type = mir->value()->type();
     MOZ_ASSERT(IsNumberType(type));
+
     unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias;
-    if (mir->value()->type() == MIRType_Int32) {
+    if (type == MIRType_Int32) {
         masm.ma_dtr(IsStore, GlobalReg, Imm32(addr), ToRegister(ins->value()));
-    } else if (mir->value()->type() == MIRType_Float32) {
+    } else if (type == MIRType_Float32) {
         VFPRegister vd(ToFloatRegister(ins->value()));
         masm.ma_vstr(vd.singleOverlay(), Operand(GlobalReg, addr));
     } else {
         masm.ma_vstr(ToFloatRegister(ins->value()), Operand(GlobalReg, addr));
     }
 }
 
 void
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -25,16 +25,17 @@ UNIFIED_SOURCES += [
     'testDefineProperty.cpp',
     'testDefinePropertyIgnoredAttributes.cpp',
     'testEnclosingFunction.cpp',
     'testErrorCopying.cpp',
     'testException.cpp',
     'testExternalStrings.cpp',
     'testFindSCCs.cpp',
     'testForOfIterator.cpp',
+    'testForwardSetProperty.cpp',
     'testFreshGlobalEvalRedefinition.cpp',
     'testFunctionProperties.cpp',
     'testGCAllocator.cpp',
     'testGCCellPtr.cpp',
     'testGCChunkPool.cpp',
     'testGCExactRooting.cpp',
     'testGCFinalizeCallback.cpp',
     'testGCHeapPostBarriers.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testForwardSetProperty.cpp
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi-tests/tests.h"
+
+BEGIN_TEST(testForwardSetProperty)
+{
+    JS::RootedValue v1(cx);
+    EVAL("var foundValue; \n"
+         "var obj1 = { set prop(val) { foundValue = this; } }; \n"
+         "obj1;",
+         &v1);
+
+    JS::RootedValue v2(cx);
+    EVAL("var obj2 = Object.create(obj1); \n"
+         "obj2;",
+         &v2);
+
+    JS::RootedValue v3(cx);
+    EVAL("var obj3 = {}; \n"
+         "obj3;",
+         &v3);
+
+    JS::RootedObject obj1(cx, &v1.toObject());
+    JS::RootedObject obj2(cx, &v2.toObject());
+    JS::RootedObject obj3(cx, &v3.toObject());
+
+    JS::RootedValue setval(cx, JS::Int32Value(42));
+
+    JS::RootedValue propkey(cx);
+    EVAL("'prop';", &propkey);
+
+    JS::RootedId prop(cx);
+    CHECK(JS_ValueToId(cx, propkey, &prop));
+
+    EXEC("function assertEq(a, b, msg) \n"
+         "{ \n"
+         "  if (!Object.is(a, b)) \n"
+         "    throw new Error('Assertion failure: ' + msg); \n"
+         "}");
+
+    // Non-strict setter
+
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
+
+    EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to setter');");
+
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
+
+    EXEC("assertEq(typeof foundValue === 'object', true, \n"
+         "         'passing 42 as receiver to non-strict setter ' + \n"
+         "         'must box');");
+
+    EXEC("assertEq(foundValue instanceof Number, true, \n"
+         "         'passing 42 as receiver to non-strict setter ' + \n"
+         "         'must box to a Number');");
+
+    EXEC("assertEq(foundValue.valueOf(), 42, \n"
+         "         'passing 42 as receiver to non-strict setter ' + \n"
+         "         'must box to new Number(42)');");
+
+    // Strict setter
+
+    EVAL("obj1 = { set prop(val) { 'use strict'; foundValue = this; } }; \n"
+         "obj1;",
+         &v1);
+
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, v3, true, setval));
+
+    EXEC("assertEq(foundValue, obj3, 'wrong receiver passed to strict setter');");
+
+    CHECK(JS_ForwardSetPropertyTo(cx, obj2, prop, setval, true, setval));
+
+
+    JS::RootedValue strictSetSupported(cx);
+    EVAL("var strictSetSupported = false; \n"
+         "Object.defineProperty(Object.prototype, \n"
+         "                      'strictSetter', \n"
+         "                      { \n"
+         "                        set(v) { \n"
+         "                          'use strict'; \n"
+         "                          strictSetSupported = \n"
+         "                            typeof this === 'number'; \n"
+         "                        } \n"
+         "                      }); \n"
+         "17..strictSetter = 42; \n"
+         "strictSetSupported;",
+         &strictSetSupported);
+    CHECK(strictSetSupported.isBoolean());
+
+    if (strictSetSupported.toBoolean()) {
+        // XXX Bug 603201 will fix this.
+        MOZ_ASSERT(false,
+                   "remove the support-testing check when bug 603201 is fixt");
+        EXEC("assertEq(foundValue, 42, \n"
+             "         '42 passed as receiver to strict setter ' + \n"
+             "         'was mangled');");
+    }
+
+    return true;
+}
+END_TEST(testForwardSetProperty)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3049,16 +3049,34 @@ JS_SetPropertyById(JSContext *cx, Handle
     RootedValue value(cx, v);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     return JSObject::setGeneric(cx, obj, obj, id, &value, false);
 }
 
+JS_PUBLIC_API(bool)
+JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
+                        bool strict, JS::HandleValue v)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    assertSameCompartment(cx, obj, id);
+    assertSameCompartment(cx, onBehalfOf);
+
+    // XXX Bug 603201 will eliminate this ToObject.
+    RootedObject receiver(cx, ToObject(cx, onBehalfOf));
+    if (!receiver)
+        return false;
+
+    RootedValue value(cx, v);
+    return JSObject::setGeneric(cx, obj, receiver, id, &value, strict);
+}
+
 static bool
 SetElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleValue vp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, vp);
 
     return JSObject::setElement(cx, obj, obj, index, vp, false);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1111,16 +1111,23 @@ ToNumberSlow(JSContext *cx, JS::Value v,
 extern JS_PUBLIC_API(bool)
 ToBooleanSlow(JS::HandleValue v);
 
 /*
  * DO NOT CALL THIS. Use JS::ToString
  */
 extern JS_PUBLIC_API(JSString*)
 ToStringSlow(JSContext *cx, JS::HandleValue v);
+
+/*
+ * DO NOT CALL THIS. Use JS::ToObject.
+ */
+extern JS_PUBLIC_API(JSObject*)
+ToObjectSlow(JSContext *cx, JS::HandleValue vp, bool reportScanStack);
+
 } /* namespace js */
 
 namespace JS {
 
 /* ES5 9.3 ToNumber. */
 MOZ_ALWAYS_INLINE bool
 ToNumber(JSContext *cx, HandleValue v, double *out)
 {
@@ -1156,16 +1163,25 @@ ToBoolean(HandleValue v)
 MOZ_ALWAYS_INLINE JSString*
 ToString(JSContext *cx, HandleValue v)
 {
     if (v.isString())
         return v.toString();
     return js::ToStringSlow(cx, v);
 }
 
+/* ES5 9.9 ToObject. */
+MOZ_ALWAYS_INLINE JSObject*
+ToObject(JSContext *cx, HandleValue vp)
+{
+    if (vp.isObject())
+        return &vp.toObject();
+    return js::ToObjectSlow(cx, vp, false);
+}
+
 /*
  * Implements ES6 draft rev 28 (2014 Oct 14) 7.1.1, second algorithm.
  *
  * Most users should not call this -- use JS::ToNumber, ToBoolean, or ToString
  * instead. This should only be called from custom convert hooks. It implements
  * the default conversion behavior shared by most objects in JS, so it's useful
  * as a fallback.
  */
@@ -3209,16 +3225,20 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
 
 extern JS_PUBLIC_API(bool)
 JS_SetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue v);
 
 extern JS_PUBLIC_API(bool)
 JS_SetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v);
 
 extern JS_PUBLIC_API(bool)
+JS_ForwardSetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue onBehalfOf,
+                        bool strict, JS::HandleValue vp);
+
+extern JS_PUBLIC_API(bool)
 JS_DeleteProperty(JSContext *cx, JS::HandleObject obj, const char *name);
 
 extern JS_PUBLIC_API(bool)
 JS_DeleteProperty2(JSContext *cx, JS::HandleObject obj, const char *name, bool *succeeded);
 
 extern JS_PUBLIC_API(bool)
 JS_DeletePropertyById(JSContext *cx, JS::HandleObject obj, jsid id);
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3612,17 +3612,23 @@ js::PrimitiveToObject(JSContext *cx, con
     if (v.isNumber())
         return NumberObject::create(cx, v.toNumber());
     if (v.isBoolean())
         return BooleanObject::create(cx, v.toBoolean());
     MOZ_ASSERT(v.isSymbol());
     return SymbolObject::create(cx, v.toSymbol());
 }
 
-/* Callers must handle the already-object case. */
+/*
+ * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
+ * already be an object, use ToObject. reportCantConvert controls how null and
+ * undefined errors are reported.
+ *
+ * Callers must handle the already-object case.
+ */
 JSObject *
 js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
 {
     MOZ_ASSERT(!val.isMagic());
     MOZ_ASSERT(!val.isObject());
 
     if (val.isNullOrUndefined()) {
         if (reportScanStack) {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1137,40 +1137,23 @@ GetObjectElementOperationPure(ThreadSafe
 /* Wrap boolean, number or string as Boolean, Number or String object. */
 extern JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v);
 
 } /* namespace js */
 
 namespace js {
 
-/*
- * Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
- * already be an object, use ToObject. reportCantConvert controls how null and
- * undefined errors are reported.
- */
-extern JSObject *
-ToObjectSlow(JSContext *cx, HandleValue vp, bool reportScanStack);
-
-/* For object conversion in e.g. native functions. */
-MOZ_ALWAYS_INLINE JSObject *
-ToObject(JSContext *cx, HandleValue vp)
-{
-    if (vp.isObject())
-        return &vp.toObject();
-    return ToObjectSlow(cx, vp, false);
-}
-
 /* For converting stack values to objects. */
 MOZ_ALWAYS_INLINE JSObject *
 ToObjectFromStack(JSContext *cx, HandleValue vp)
 {
     if (vp.isObject())
         return &vp.toObject();
-    return ToObjectSlow(cx, vp, true);
+    return js::ToObjectSlow(cx, vp, true);
 }
 
 template<XDRMode mode>
 bool
 XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleNativeObject obj);
 
 extern JSObject *
 CloneObjectLiteral(JSContext *cx, HandleObject parent, HandleObject srcObj);
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1106,17 +1106,26 @@ ScriptedDirectProxyHandler::construct(JS
     }
     return true;
 }
 
 bool
 ScriptedDirectProxyHandler::isCallable(JSObject *obj) const
 {
     MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedDirectProxyHandler::singleton);
-    return obj->as<ProxyObject>().extra(IS_CALLABLE_EXTRA).toBoolean();
+    uint32_t callConstruct = obj->as<ProxyObject>().extra(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
+    return !!(callConstruct & IS_CALLABLE);
+}
+
+bool
+ScriptedDirectProxyHandler::isConstructor(JSObject *obj) const
+{
+    MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedDirectProxyHandler::singleton);
+    uint32_t callConstruct = obj->as<ProxyObject>().extra(IS_CALLCONSTRUCT_EXTRA).toPrivateUint32();
+    return !!(callConstruct & IS_CONSTRUCTOR);
 }
 
 const char ScriptedDirectProxyHandler::family = 0;
 const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
 
 bool
 js::proxy(JSContext *cx, unsigned argc, jsval *vp)
 {
@@ -1134,19 +1143,23 @@ js::proxy(JSContext *cx, unsigned argc, 
         return false;
     RootedValue priv(cx, ObjectValue(*target));
     JSObject *proxy_ =
         NewProxyObject(cx, &ScriptedDirectProxyHandler::singleton,
                        priv, TaggedProto::LazyProto, cx->global());
     if (!proxy_)
         return false;
     Rooted<ProxyObject*> proxy(cx, &proxy_->as<ProxyObject>());
-    bool targetIsCallable = target->isCallable(); // Can GC - don't compute it inline.
     proxy->setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
-    proxy->setExtra(ScriptedDirectProxyHandler::IS_CALLABLE_EXTRA, BooleanValue(targetIsCallable));
+
+    // Assign [[Call]] and [[Construct]]
+    uint32_t callable = target->isCallable() ? ScriptedDirectProxyHandler::IS_CALLABLE : 0;
+    uint32_t constructor = target->isConstructor() ? ScriptedDirectProxyHandler::IS_CONSTRUCTOR : 0;
+    proxy->as<ProxyObject>().setExtra(ScriptedDirectProxyHandler::IS_CALLCONSTRUCT_EXTRA,
+                                      PrivateUint32Value(callable | constructor));
     args.rval().setObject(*proxy);
     return true;
 }
 
 static bool
 RevokeProxy(JSContext *cx, unsigned argc, Value *vp)
 {
     CallReceiver rec = CallReceiverFromVp(vp);
--- a/js/src/proxy/ScriptedDirectProxyHandler.h
+++ b/js/src/proxy/ScriptedDirectProxyHandler.h
@@ -60,30 +60,30 @@ class ScriptedDirectProxyHandler : publi
     // filter. [[GetOwnProperty]] could potentially change the enumerability of
     // the target's properties.
     virtual bool getOwnEnumerablePropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const MOZ_OVERRIDE {
         return BaseProxyHandler::getOwnEnumerablePropertyKeys(cx, proxy, props);
     }
 
     virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
-    virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
-        // For now we maintain the broken behavior that a scripted proxy is constructable if it's
-        // callable. See bug 929467.
-        return isCallable(obj);
-    }
+    virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE;
+
     virtual bool isScripted() const MOZ_OVERRIDE { return true; }
 
     static const char family;
     static const ScriptedDirectProxyHandler singleton;
 
     // The "proxy extra" slot index in which the handler is stored. Revocable proxies need to set
     // this at revocation time.
     static const int HANDLER_EXTRA = 0;
-    static const int IS_CALLABLE_EXTRA = 1;
+    static const int IS_CALLCONSTRUCT_EXTRA = 1;
+    // Bitmasks for the "call/construct" slot
+    static const int IS_CALLABLE    = 1 << 0;
+    static const int IS_CONSTRUCTOR = 1 << 1;
     // The "function extended" slot index in which the revocation object is stored. Per spec, this
     // is to be cleared during the first revocation.
     static const int REVOKE_SLOT = 0;
 };
 
 bool
 proxy(JSContext *cx, unsigned argc, jsval *vp);
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedArray/every-and-some.js
@@ -0,0 +1,261 @@
+const constructors = [
+    Int8Array,
+    Uint8Array,
+    Uint8ClampedArray,
+    Int16Array,
+    Uint16Array,
+    Int32Array,
+    Uint32Array,
+    Float32Array,
+    Float64Array
+];
+
+// Tests for TypedArray#every.
+for (var constructor of constructors) {
+    assertEq(constructor.prototype.every.length, 1);
+
+    // Basic tests.
+    assertEq(new constructor([1, 3, 5]).every(v => v % 2), true);
+    assertEq(new constructor([1, 3, 5]).every(v => v > 2), false);
+    assertEq(new constructor(10).every(v => v === 0), true);
+    assertEq(new constructor().every(v => v > 1), true);
+
+    var arr = new constructor([1, 2, 3, 4, 5]);
+    var sum = 0;
+    var count = 0;
+    assertEq(arr.every((v, k, o) => {
+        count++;
+        sum += v;
+        assertEq(k, v - 1);
+        assertEq(o, arr);
+        return v < 3;
+    }), false);
+    assertEq(sum, 6);
+    assertEq(count, 3);
+
+    // Tests for `thisArg` argument.
+    function assertThisArg(thisArg, thisValue) {
+        // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+        assertEq(arr.every(function() {
+            assertDeepEq(this, thisValue);
+            return true;
+        }, thisArg), true);
+
+        // In strict mode, `this` strictly equals `thisArg`.
+        assertEq(arr.every(function() {
+            "use strict";
+            assertDeepEq(this, thisArg);
+            return true;
+        }, thisArg), true);
+
+        // Passing `thisArg` has no effect if callback is an arrow function.
+        var self = this;
+        assertEq(arr.every(() => {
+            assertEq(this, self);
+            return true;
+        }, thisArg), true);
+    }
+    assertThisArg([1, 2, 3], [1, 2, 3]);
+    assertThisArg(Object, Object);
+    assertThisArg(1, Object(1));
+    assertThisArg("1", Object("1"));
+    assertThisArg(false, Object(false));
+    assertThisArg(undefined, this);
+    assertThisArg(null, this);
+
+    // Throw an exception in the callback.
+    var sum = 0;
+    var count = 0;
+    var thrown = false;
+    try {
+        arr.every((v, k, o) => {
+            count++;
+            sum += v;
+            assertEq(k, v - 1);
+            assertEq(o, arr);
+            if (v === 3) {
+                throw "every";
+            }
+            return true
+        })
+    } catch(e) {
+        assertEq(e, "every");
+        thrown = true;
+    }
+    assertEq(thrown, true);
+    assertEq(sum, 6);
+    assertEq(count, 3);
+
+    // There is no callback or callback is not a function.
+    assertThrowsInstanceOf(() => {
+        arr.every();
+    }, TypeError);
+    var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+    invalidCallbacks.forEach(callback => {
+        assertThrowsInstanceOf(() => {
+            arr.every(callback);
+        }, TypeError);
+    })
+
+    // Callback is a generator.
+    arr.every(function*(){
+        throw "This line will not be executed";
+    });
+
+    // Called from other globals.
+    if (typeof newGlobal === "function") {
+        var every = newGlobal()[constructor.name].prototype.every;
+        var sum = 0;
+        assertEq(every.call(new constructor([1, 2, 3]), v => sum += v), true);
+        assertEq(sum, 6);
+    }
+
+    // Throws if `this` isn't a TypedArray.
+    var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+    invalidReceivers.forEach(invalidReceiver => {
+        assertThrowsInstanceOf(() => {
+            constructor.prototype.every.call(invalidReceiver, () => true);
+        }, TypeError, "Assert that every fails if this value is not a TypedArray");
+    });
+    // FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
+    constructor.prototype.every.call(new Proxy(new constructor(), {}), () => true);
+
+    // Test that the length getter is never called.
+    assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+        get() {
+            throw new Error("length accessor called");
+        }
+    }).every(() => true), true);
+}
+
+assertEq(new Float32Array([undefined, , NaN]).every(v => Object.is(v, NaN)), true);
+assertEq(new Float64Array([undefined, , NaN]).every(v => Object.is(v, NaN)), true);
+
+// Tests for TypedArray#some.
+for (var constructor of constructors) {
+    assertEq(constructor.prototype.some.length, 1);
+
+    // Basic tests.
+    assertEq(new constructor([1, 2, 3]).some(v => v % 2), true);
+    assertEq(new constructor([0, 2, 4]).some(v => v % 2), false);
+    assertEq(new constructor([1, 3, 5]).some(v => v > 2), true);
+    assertEq(new constructor([1, 3, 5]).some(v => v < 0), false);
+    assertEq(new constructor(10).some(v => v !== 0), false);
+    assertEq(new constructor().some(v => v > 1), false);
+
+    var arr = new constructor([1, 2, 3, 4, 5]);
+    var sum = 0;
+    var count = 0;
+    assertEq(arr.some((v, k, o) => {
+        count++;
+        sum += v;
+        assertEq(k, v - 1);
+        assertEq(o, arr);
+        return v > 2;
+    }), true);
+    assertEq(sum, 6);
+    assertEq(count, 3);
+
+    // Tests for `thisArg` argument.
+    function assertThisArg(thisArg, thisValue) {
+        // In sloppy mode, `this` could be global object or a wrapper of `thisArg`.
+        assertEq(arr.some(function() {
+            assertDeepEq(this, thisValue);
+            return false;
+        }, thisArg), false);
+
+        // In strict mode, `this` strictly equals `thisArg`.
+        assertEq(arr.some(function() {
+            "use strict";
+            assertDeepEq(this, thisArg);
+            return false;
+        }, thisArg), false);
+
+        // Passing `thisArg` has no effect if callback is an arrow function.
+        var self = this;
+        assertEq(arr.some(() => {
+            assertEq(this, self);
+            return false;
+        }, thisArg), false);
+    }
+    assertThisArg([1, 2, 3], [1, 2, 3]);
+    assertThisArg(Object, Object);
+    assertThisArg(1, Object(1));
+    assertThisArg("1", Object("1"));
+    assertThisArg(false, Object(false));
+    assertThisArg(undefined, this);
+    assertThisArg(null, this);
+
+    // Throw an exception in the callback.
+    var sum = 0;
+    var count = 0;
+    var thrown = false;
+    try {
+        arr.some((v, k, o) => {
+            count++;
+            sum += v;
+            assertEq(k, v - 1);
+            assertEq(o, arr);
+            if (v === 3) {
+                throw "some";
+            }
+            return false
+        })
+    } catch(e) {
+        assertEq(e, "some");
+        thrown = true;
+    }
+    assertEq(thrown, true);
+    assertEq(sum, 6);
+    assertEq(count, 3);
+
+    // There is no callback or callback is not a function.
+    assertThrowsInstanceOf(() => {
+        arr.some();
+    }, TypeError);
+    var invalidCallbacks = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+    invalidCallbacks.forEach(callback => {
+        assertThrowsInstanceOf(() => {
+            arr.some(callback);
+        }, TypeError);
+    })
+
+    // Callback is a generator.
+    arr.some(function*(){
+        throw "This line will not be executed";
+    });
+
+    // Called from other globals.
+    if (typeof newGlobal === "function") {
+        var some = newGlobal()[constructor.name].prototype.some;
+        var sum = 0;
+        assertEq(some.call(new constructor([1, 2, 3]), v => {
+            sum += v;
+            return false;
+        }), false);
+        assertEq(sum, 6);
+    }
+
+    // Throws if `this` isn't a TypedArray.
+    var invalidReceivers = [undefined, null, 1, false, "", Symbol(), [], {}, /./];
+    invalidReceivers.forEach(invalidReceiver => {
+        assertThrowsInstanceOf(() => {
+            constructor.prototype.some.call(invalidReceiver, () => true);
+        }, TypeError, "Assert that some fails if this value is not a TypedArray");
+    });
+    // FIXME: Should throw exception if `this` is a proxy, see bug 1115361.
+    constructor.prototype.some.call(new Proxy(new constructor(), {}), () => false);
+
+    // Test that the length getter is never called.
+    assertEq(Object.defineProperty(new constructor([1, 2, 3]), "length", {
+        get() {
+            throw new Error("length accessor called");
+        }
+    }).some(() => false), false);
+}
+
+assertEq(new Float32Array([undefined, , NaN]).some(v => v === v), false);
+assertEq(new Float64Array([undefined, , NaN]).some(v => v === v), false);
+
+if (typeof reportCompare === "function")
+    reportCompare(true, true);
\ No newline at end of file
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -921,16 +921,18 @@ GlobalHelperThreadState::finishParseTask
     assertSameCompartment(cx, script);
 
     // Report any error or warnings generated during the parse, and inform the
     // debugger about the compiled scripts.
     for (size_t i = 0; i < parseTask->errors.length(); i++)
         parseTask->errors[i]->throwError(cx);
     if (parseTask->overRecursed)
         js_ReportOverRecursed(cx);
+    if (cx->isExceptionPending())
+        return nullptr;
 
     if (script) {
         // The Debugger only needs to be told about the topmost script that was compiled.
         GlobalObject *compileAndGoGlobal = nullptr;
         if (script->compileAndGo())
             compileAndGoGlobal = &script->global();
         Debugger::onNewScript(cx, script, compileAndGoGlobal);
 
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -480,22 +480,72 @@ GetObjectElementOperation(JSContext *cx,
     assertSameCompartmentDebugOnly(cx, res);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 GetPrimitiveElementOperation(JSContext *cx, JSOp op, JS::HandleValue receiver,
                              HandleValue key, MutableHandleValue res)
 {
-    // FIXME: We shouldn't be boxing here (bug 603201).
+    MOZ_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
+
+    // FIXME: We shouldn't be boxing here or exposing the boxed object as
+    //        receiver anywhere below (bug 603201).
     RootedObject boxed(cx, ToObjectFromStack(cx, receiver));
     if (!boxed)
         return false;
 
-    return GetObjectElementOperation(cx, op, boxed, key, res);
+    do {
+        uint32_t index;
+        if (IsDefinitelyIndex(key, &index)) {
+            if (JSObject::getElementNoGC(cx, boxed, boxed, index, res.address()))
+                break;
+
+            if (!JSObject::getElement(cx, boxed, boxed, index, res))
+                return false;
+            break;
+        }
+
+        if (IsSymbolOrSymbolWrapper(key)) {
+            RootedId id(cx, SYMBOL_TO_JSID(ToSymbolPrimitive(key)));
+            if (!JSObject::getGeneric(cx, boxed, boxed, id, res))
+                return false;
+            break;
+        }
+
+        if (JSAtom *name = ToAtom<NoGC>(cx, key)) {
+            if (name->isIndex(&index)) {
+                if (JSObject::getElementNoGC(cx, boxed, boxed, index, res.address()))
+                    break;
+            } else {
+                if (JSObject::getPropertyNoGC(cx, boxed, boxed, name->asPropertyName(),
+                                              res.address()))
+                {
+                    break;
+                }
+            }
+        }
+
+        JSAtom *name = ToAtom<CanGC>(cx, key);
+        if (!name)
+            return false;
+
+        if (name->isIndex(&index)) {
+            if (!JSObject::getElement(cx, boxed, boxed, index, res))
+                return false;
+        } else {
+            if (!JSObject::getProperty(cx, boxed, boxed, name->asPropertyName(), res))
+                return false;
+        }
+    } while (false);
+
+    // Note: we don't call a __noSuchMethod__ hook when |this| was primitive.
+
+    assertSameCompartmentDebugOnly(cx, res);
+    return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
 GetElemOptimizedArguments(JSContext *cx, AbstractFramePtr frame, MutableHandleValue lref,
                           HandleValue rref, MutableHandleValue res, bool *done)
 {
     MOZ_ASSERT(!*done);
 
--- a/js/src/vm/RegExpObject.cpp
+++ b/js/src/vm/RegExpObject.cpp
@@ -705,16 +705,18 @@ RegExpCompartment::createMatchResultTemp
     RootedArrayObject templateObject(cx, NewDenseUnallocatedArray(cx, 0, nullptr, TenuredObject));
     if (!templateObject)
         return matchResultTemplateObject_; // = nullptr
 
     // Create a new type for the template.
     Rooted<TaggedProto> proto(cx, templateObject->getTaggedProto());
     types::TypeObject *type =
         cx->compartment()->types.newTypeObject(cx, templateObject->getClass(), proto);
+    if (!type)
+        return matchResultTemplateObject_; // = nullptr
     templateObject->setType(type);
 
     /* Set dummy index property */
     RootedValue index(cx, Int32Value(0));
     if (!baseops::DefineProperty(cx, templateObject, cx->names().index, index, nullptr, nullptr,
                                  JSPROP_ENUMERATE))
     {
         return matchResultTemplateObject_; // = nullptr
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1487,18 +1487,19 @@ class AsmJSActivation : public Activatio
     static unsigned offsetOfContext() { return offsetof(AsmJSActivation, cx_); }
     static unsigned offsetOfResumePC() { return offsetof(AsmJSActivation, resumePC_); }
 
     // Written by JIT code:
     static unsigned offsetOfEntrySP() { return offsetof(AsmJSActivation, entrySP_); }
     static unsigned offsetOfFP() { return offsetof(AsmJSActivation, fp_); }
     static unsigned offsetOfExitReason() { return offsetof(AsmJSActivation, exitReason_); }
 
-    // Set from SIGSEGV handler:
+    // Read/written from SIGSEGV handler:
     void setResumePC(void *pc) { resumePC_ = pc; }
+    void *resumePC() const { return resumePC_; }
 };
 
 // A FrameIter walks over the runtime's stack of JS script activations,
 // abstracting over whether the JS scripts were running in the interpreter or
 // different modes of compiled code.
 //
 // FrameIter is parameterized by what it includes in the stack iteration:
 //  - The SavedOption controls whether FrameIter stops when it finds an
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -776,23 +776,25 @@ TypedArrayObject::subarray(JSContext *cx
 }
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::protoFunctions[] = {
     JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0),                          \
     JS_FN("subarray", TypedArrayObject::subarray, 2, 0),
     JS_FN("set", TypedArrayObject::set, 2, 0),
     JS_FN("copyWithin", TypedArrayObject::copyWithin, 2, 0),
+    JS_SELF_HOSTED_FN("every", "TypedArrayEvery", 2, 0),
     JS_SELF_HOSTED_FN("fill", "TypedArrayFill", 3, 0),
     JS_SELF_HOSTED_FN("find", "TypedArrayFind", 2, 0),
     JS_SELF_HOSTED_FN("findIndex", "TypedArrayFindIndex", 2, 0),
     JS_SELF_HOSTED_FN("indexOf", "TypedArrayIndexOf", 2, 0),
     JS_SELF_HOSTED_FN("join", "TypedArrayJoin", 1, 0),
     JS_SELF_HOSTED_FN("lastIndexOf", "TypedArrayLastIndexOf", 2, 0),
     JS_SELF_HOSTED_FN("reverse", "TypedArrayReverse", 0, 0),
+    JS_SELF_HOSTED_FN("some", "TypedArraySome", 2, 0),
 #ifdef NIGHTLY_BUILD
     JS_SELF_HOSTED_FN("includes", "TypedArrayIncludes", 2, 0),
 #endif
     JS_FS_END
 };
 
 /* static */ const JSFunctionSpec
 TypedArrayObject::staticFunctions[] = {
--- a/js/xpconnect/src/nsScriptError.cpp
+++ b/js/xpconnect/src/nsScriptError.cpp
@@ -6,16 +6,18 @@
 
 /*
  * nsIScriptError implementation.  Defined here, lacking a JS-specific
  * place to put XPCOM things.
  */
 
 #include "xpcprivate.h"
 #include "jsprf.h"
+#include "MainThreadUtils.h"
+#include "mozilla/Assertions.h"
 #include "nsGlobalWindow.h"
 #include "nsPIDOMWindow.h"
 #include "nsILoadContext.h"
 #include "nsIDocShell.h"
 
 NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError)
 
 nsScriptError::nsScriptError()
@@ -24,22 +26,53 @@ nsScriptError::nsScriptError()
        mLineNumber(0),
        mSourceLine(),
        mColumnNumber(0),
        mFlags(0),
        mCategory(),
        mOuterWindowID(0),
        mInnerWindowID(0),
        mTimeStamp(0),
+       mInitializedOnMainThread(false),
        mIsFromPrivateWindow(false)
 {
 }
 
 nsScriptError::~nsScriptError() {}
 
+void
+nsScriptError::InitializeOnMainThread()
+{
+    MOZ_ASSERT(NS_IsMainThread());
+    MOZ_ASSERT(!mInitializedOnMainThread);
+
+    if (mInnerWindowID) {
+        nsGlobalWindow* window =
+          nsGlobalWindow::GetInnerWindowWithId(mInnerWindowID);
+        if (window) {
+            nsPIDOMWindow* outer = window->GetOuterWindow();
+            if (outer)
+                mOuterWindowID = outer->WindowID();
+
+            nsIDocShell* docShell = window->GetDocShell();
+            nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+
+            if (loadContext) {
+                // Never mark exceptions from chrome windows as having come from
+                // private windows, since we always want them to be reported.
+                nsIPrincipal* winPrincipal = window->GetPrincipal();
+                mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
+                                       !nsContentUtils::IsSystemPrincipal(winPrincipal);
+            }
+        }
+    }
+
+    mInitializedOnMainThread = true;
+}
+
 // nsIConsoleMessage methods
 NS_IMETHODIMP
 nsScriptError::GetMessageMoz(char16_t **result) {
     nsresult rv;
 
     nsAutoCString message;
     rv = ToString(message);
     if (NS_FAILED(rv))
@@ -135,36 +168,18 @@ nsScriptError::InitWithWindowID(const ns
     mLineNumber = lineNumber;
     mSourceLine.Assign(sourceLine);
     mColumnNumber = columnNumber;
     mFlags = flags;
     mCategory = category;
     mTimeStamp = JS_Now() / 1000;
     mInnerWindowID = aInnerWindowID;
 
-    if (aInnerWindowID) {
-        nsGlobalWindow* window =
-          nsGlobalWindow::GetInnerWindowWithId(aInnerWindowID);
-        if (window) {
-            nsPIDOMWindow* outer = window->GetOuterWindow();
-            if (outer)
-                mOuterWindowID = outer->WindowID();
-
-            nsIDocShell* docShell = window->GetDocShell();
-            nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
-
-            if (loadContext) {
-                // Never mark exceptions from chrome windows as having come from
-                // private windows, since we always want them to be reported.
-                nsIPrincipal* winPrincipal = window->GetPrincipal();
-                mIsFromPrivateWindow = loadContext->UsePrivateBrowsing() &&
-                                       !nsContentUtils::IsSystemPrincipal(winPrincipal);
-            }
-
-        }
+    if (aInnerWindowID && NS_IsMainThread()) {
+        InitializeOnMainThread();
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::ToString(nsACString& /*UTF8*/ aResult)
 {
@@ -224,16 +239,24 @@ nsScriptError::ToString(nsACString& /*UT
     aResult.Assign(temp);
     JS_smprintf_free(temp);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetOuterWindowID(uint64_t *aOuterWindowID)
 {
+    NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread,
+                     "This can't be safely determined off the main thread, "
+                     "returning an inaccurate value!");
+
+    if (!mInitializedOnMainThread && NS_IsMainThread()) {
+        InitializeOnMainThread();
+    }
+
     *aOuterWindowID = mOuterWindowID;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetInnerWindowID(uint64_t *aInnerWindowID)
 {
     *aInnerWindowID = mInnerWindowID;
@@ -245,11 +268,19 @@ nsScriptError::GetTimeStamp(int64_t *aTi
 {
     *aTimeStamp = mTimeStamp;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsScriptError::GetIsFromPrivateWindow(bool *aIsFromPrivateWindow)
 {
+    NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread,
+                     "This can't be safely determined off the main thread, "
+                     "returning an inaccurate value!");
+
+    if (!mInitializedOnMainThread && NS_IsMainThread()) {
+        InitializeOnMainThread();
+    }
+
     *aIsFromPrivateWindow = mIsFromPrivateWindow;
     return NS_OK;
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -72,16 +72,17 @@
 /* All the XPConnect private declarations - only include locally. */
 
 #ifndef xpcprivate_h___
 #define xpcprivate_h___
 
 #include "mozilla/Alignment.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TimeStamp.h"
 
@@ -2966,26 +2967,33 @@ public:
 
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSICONSOLEMESSAGE
     NS_DECL_NSISCRIPTERROR
 
 private:
     virtual ~nsScriptError();
 
+    void
+    InitializeOnMainThread();
+
     nsString mMessage;
     nsString mSourceName;
     uint32_t mLineNumber;
     nsString mSourceLine;
     uint32_t mColumnNumber;
     uint32_t mFlags;
     nsCString mCategory;
+    // mOuterWindowID is set on the main thread from InitializeOnMainThread().
     uint64_t mOuterWindowID;
     uint64_t mInnerWindowID;
     int64_t mTimeStamp;
+    // mInitializedOnMainThread and mIsFromPrivateWindow are set on the main
+    // thread from InitializeOnMainThread().
+    mozilla::Atomic<bool> mInitializedOnMainThread;
     bool mIsFromPrivateWindow;
 };
 
 /******************************************************************************
  * Handles pre/post script processing.
  */
 class MOZ_STACK_CLASS AutoScriptEvaluate
 {
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -176,17 +176,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     gPrototypeProperties['Array'] = gPrototypeProperties['Array'].concat(pjsMethods);
   }
   for (var c of typedArrayClasses) {
     gPrototypeProperties[c] = ["constructor", "BYTES_PER_ELEMENT"];
   }
   gPrototypeProperties['TypedArray'] =
     ["length", "buffer", "byteLength", "byteOffset", kIteratorSymbol, "subarray",
      "set", "copyWithin", "find", "findIndex", "indexOf", "lastIndexOf", "reverse",
-     "join"];
+     "join", "every", "some"];
   if (isNightlyBuild) {
     gPrototypeProperties['TypedArray'].push('includes');
   }
   for (var c of errorObjectClasses) {
       gPrototypeProperties[c] = ["constructor", "name",
                                  // We don't actually resolve these empty data properties
                                  // onto the Xray prototypes, but we list them here to make
                                  // the test happy.
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -756,43 +756,43 @@ nsRefreshDriver::AdvanceTimeAndRefresh(i
   mozilla::dom::AutoNoJSAPI nojsapi;
   DoTick();
 }
 
 void
 nsRefreshDriver::RestoreNormalRefresh()
 {
   mTestControllingRefreshes = false;
-  EnsureTimerStarted(false);
+  EnsureTimerStarted(eAllowTimeToGoBackwards);
   mCompletedTransaction = mPendingTransaction;
 }
 
 TimeStamp
 nsRefreshDriver::MostRecentRefresh() const
 {
-  const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted(false);
+  const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
 
   return mMostRecentRefresh;
 }
 
 int64_t
 nsRefreshDriver::MostRecentRefreshEpochTime() const
 {
-  const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted(false);
+  const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
 
   return mMostRecentRefreshEpochTime;
 }
 
 bool
 nsRefreshDriver::AddRefreshObserver(nsARefreshObserver* aObserver,
                                     mozFlushType aFlushType)
 {
   ObserverArray& array = ArrayFor(aFlushType);
   bool success = array.AppendElement(aObserver) != nullptr;
-  EnsureTimerStarted(false);
+  EnsureTimerStarted();
   return success;
 }
 
 bool
 nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver* aObserver,
                                        mozFlushType aFlushType)
 {
   ObserverArray& array = ArrayFor(aFlushType);
@@ -823,17 +823,17 @@ nsRefreshDriver::AddImageRequest(imgIReq
     ImageStartData* start = mStartTable.Get(delay);
     if (!start) {
       start = new ImageStartData();
       mStartTable.Put(delay, start);
     }
     start->mEntries.PutEntry(aRequest);
   }
 
-  EnsureTimerStarted(false);
+  EnsureTimerStarted();
 
   return true;
 }
 
 void
 nsRefreshDriver::RemoveImageRequest(imgIRequest* aRequest)
 {
   // Try to remove from both places, just in case, because we can't tell
@@ -844,23 +844,23 @@ nsRefreshDriver::RemoveImageRequest(imgI
     ImageStartData* start = mStartTable.Get(delay);
     if (start) {
       start->mEntries.RemoveEntry(aRequest);
     }
   }
 }
 
 void
-nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer)
+nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags)
 {
   if (mTestControllingRefreshes)
     return;
 
   // will it already fire, and no other changes needed?
-  if (mActiveTimer && !aAdjustingTimer)
+  if (mActiveTimer && !(aFlags & eAdjustingTimer))
     return;
 
   if (IsFrozen() || !mPresContext) {
     // If we don't want to start it now, or we've been disconnected.
     StopTimer();
     return;
   }
 
@@ -886,21 +886,29 @@ nsRefreshDriver::EnsureTimerStarted(bool
     mActiveTimer = newTimer;
     mActiveTimer->AddRefreshDriver(this);
   }
 
   // Since the different timers are sampled at different rates, when switching
   // timers, the most recent refresh of the new timer may be *before* the
   // most recent refresh of the old timer. However, the refresh driver time
   // should not go backwards so we clamp the most recent refresh time.
+  //
+  // The one exception to this is when we are restoring the refresh driver
+  // from test control in which case the time is expected to go backwards
+  // (see bug 1043078).
   mMostRecentRefresh =
-    std::max(mActiveTimer->MostRecentRefresh(), mMostRecentRefresh);
+    aFlags & eAllowTimeToGoBackwards
+    ? mActiveTimer->MostRecentRefresh()
+    : std::max(mActiveTimer->MostRecentRefresh(), mMostRecentRefresh);
   mMostRecentRefreshEpochTime =
-    std::max(mActiveTimer->MostRecentRefreshEpochTime(),
-             mMostRecentRefreshEpochTime);
+    aFlags & eAllowTimeToGoBackwards
+    ? mActiveTimer->MostRecentRefreshEpochTime()
+    : std::max(mActiveTimer->MostRecentRefreshEpochTime(),
+               mMostRecentRefreshEpochTime);
 }
 
 void
 nsRefreshDriver::StopTimer()
 {
   if (!mActiveTimer)
     return;
 
@@ -1498,17 +1506,17 @@ nsRefreshDriver::Thaw()
 
   if (mFreezeCount == 0) {
     if (ObserverCount() || ImageRequestCount()) {
       // FIXME: This isn't quite right, since our EnsureTimerStarted call
       // updates our mMostRecentRefresh, but the DoRefresh call won't run
       // and notify our observers until we get back to the event loop.
       // Thus MostRecentRefresh() will lie between now and the DoRefresh.
       NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsRefreshDriver::DoRefresh));
-      EnsureTimerStarted(false);
+      EnsureTimerStarted();
     }
   }
 }
 
 void
 nsRefreshDriver::FinishedWaitingForTransaction()
 {
   mWaitingForTransaction = false;
@@ -1626,17 +1634,17 @@ nsRefreshDriver::IsWaitingForPaint(mozil
 void
 nsRefreshDriver::SetThrottled(bool aThrottled)
 {
   if (aThrottled != mThrottled) {
     mThrottled = aThrottled;
     if (mActiveTimer) {
       // We want to switch our timer type here, so just stop and
       // restart the timer.
-      EnsureTimerStarted(true);
+      EnsureTimerStarted(eAdjustingTimer);
     }
   }
 }
 
 void
 nsRefreshDriver::DoRefresh()
 {
   // Don't do a refresh unless we're in a state where we should be refreshing.
@@ -1656,30 +1664,30 @@ nsRefreshDriver::IsRefreshObserver(nsARe
 #endif
 
 void
 nsRefreshDriver::ScheduleViewManagerFlush()
 {
   NS_ASSERTION(mPresContext->IsRoot(),
                "Should only schedule view manager flush on root prescontexts");
   mViewManagerFlushIsPending = true;
-  EnsureTimerStarted(false);
+  EnsureTimerStarted();
 }
 
 void
 nsRefreshDriver::ScheduleFrameRequestCallbacks(nsIDocument* aDocument)
 {
   NS_ASSERTION(mFrameRequestCallbackDocs.IndexOf(aDocument) ==
                mFrameRequestCallbackDocs.NoIndex,
                "Don't schedule the same document multiple times");
   mFrameRequestCallbackDocs.AppendElement(aDocument);
 
   // make sure that the timer is running
   ConfigureHighPrecision();
-  EnsureTimerStarted(false);
+  EnsureTimerStarted();
 }
 
 void
 nsRefreshDriver::RevokeFrameRequestCallbacks(nsIDocument* aDocument)
 {
   mFrameRequestCallbackDocs.RemoveElement(aDocument);
   ConfigureHighPrecision();
   // No need to worry about restarting our timer in slack mode if it's already
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -154,17 +154,17 @@ public:
     // We only get the cause for the first observer each frame because capturing
     // a stack is expensive. This is still useful if (1) you're trying to remove
     // all flushes for a particial frame or (2) the costly flush is triggered
     // near the call site where the first observer is triggered.
     if (!mStyleCause) {
       mStyleCause = profiler_get_backtrace();
     }
     bool appended = mStyleFlushObservers.AppendElement(aShell) != nullptr;
-    EnsureTimerStarted(false);
+    EnsureTimerStarted();
 
     return appended;
   }
   void RemoveStyleFlushObserver(nsIPresShell* aShell) {
     mStyleFlushObservers.RemoveElement(aShell);
   }
   bool AddLayoutFlushObserver(nsIPresShell* aShell) {
     NS_ASSERTION(!IsLayoutFlushObserver(aShell),
@@ -172,30 +172,30 @@ public:
     // We only get the cause for the first observer each frame because capturing
     // a stack is expensive. This is still useful if (1) you're trying to remove
     // all flushes for a particial frame or (2) the costly flush is triggered
     // near the call site where the first observer is triggered.
     if (!mReflowCause) {
       mReflowCause = profiler_get_backtrace();
     }
     bool appended = mLayoutFlushObservers.AppendElement(aShell) != nullptr;
-    EnsureTimerStarted(false);
+    EnsureTimerStarted();
     return appended;
   }
   void RemoveLayoutFlushObserver(nsIPresShell* aShell) {
     mLayoutFlushObservers.RemoveElement(aShell);
   }
   bool IsLayoutFlushObserver(nsIPresShell* aShell) {
     return mLayoutFlushObservers.Contains(aShell);
   }
   bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) {
     NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell),
 		 "Double-adding style flush observer");
     bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr;
-    EnsureTimerStarted(false);
+    EnsureTimerStarted();
     return appended;
   }
   void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) {
     mPresShellsToInvalidateIfHidden.RemoveElement(aShell);
   }
 
   /**
    * Remember whether our presshell's view manager needs a flush
@@ -293,17 +293,22 @@ private:
 
     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
     RequestTable mEntries;
   };
   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
 
   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
-  void EnsureTimerStarted(bool aAdjustingTimer);
+  enum EnsureTimerStartedFlags {
+    eNone = 0,
+    eAdjustingTimer = 1 << 0,
+    eAllowTimeToGoBackwards = 1 << 1
+  };
+  void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone);
   void StopTimer();
 
   uint32_t ObserverCount() const;
   uint32_t ImageRequestCount() const;
   static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
                                                 void* aUserArg);
   static PLDHashOperator StartTableRequestCounter(const uint32_t& aKey,
                                                   ImageStartData* aEntry,
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -76,29 +76,28 @@ private:
   nsListControlFrame  *mFrame;
 };
 
 //---------------------------------------------------------
 nsContainerFrame*
 NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   nsListControlFrame* it =
-    new (aPresShell) nsListControlFrame(aPresShell, aPresShell->GetDocument(), aContext);
+    new (aPresShell) nsListControlFrame(aContext);
 
   it->AddStateBits(NS_FRAME_INDEPENDENT_SELECTION);
 
   return it;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsListControlFrame)
 
 //---------------------------------------------------------
-nsListControlFrame::nsListControlFrame(
-  nsIPresShell* aShell, nsIDocument* aDocument, nsStyleContext* aContext)
-  : nsHTMLScrollFrame(aShell, aContext, false),
+nsListControlFrame::nsListControlFrame(nsStyleContext* aContext)
+  : nsHTMLScrollFrame(aContext, false),
     mMightNeedSecondPass(false),
     mHasPendingInterruptAtStartOfReflow(false),
     mDropdownCanGrow(false),
     mForceSelection(false),
     mLastDropdownComputedHeight(NS_UNCONSTRAINEDSIZE)
 {
   mComboboxFrame      = nullptr;
   mChangesSinceDragStart = false;
--- a/layout/forms/nsListControlFrame.h
+++ b/layout/forms/nsListControlFrame.h
@@ -310,17 +310,17 @@ protected:
                                        int32_t aNumOptions, int32_t aDoAdjustInc, int32_t aDoAdjustIncNext);
 
   /**
    * Resets the select back to it's original default values;
    * those values as determined by the original HTML
    */
   virtual void ResetList(bool aAllowScrolling);
 
-  nsListControlFrame(nsIPresShell* aShell, nsIDocument* aDocument, nsStyleContext* aContext);
+  explicit nsListControlFrame(nsStyleContext* aContext);
   virtual ~nsListControlFrame();
 
   /**
    * Sets the mSelectedIndex and mOldSelectedIndex from figuring out what 
    * item was selected using content
    * @param aPoint the event point, in listcontrolframe coordinates
    * @return NS_OK if it successfully found the selection
    */
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -49,17 +49,17 @@
 
 #define DEFAULT_COLUMN_WIDTH 20
 
 using namespace mozilla;
 
 nsIFrame*
 NS_NewTextControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsTextControlFrame(aPresShell, aContext);
+  return new (aPresShell) nsTextControlFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsTextControlFrame)
 
 NS_QUERYFRAME_HEAD(nsTextControlFrame)
   NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
   NS_QUERYFRAME_ENTRY(nsITextControlFrame)
@@ -94,17 +94,17 @@ public:
   }
   bool EnteredMoreThanOnce() const { return !mFirstEntry; }
 private:
   nsTextControlFrame &mFrame;
   bool mFirstEntry;
 };
 #endif
 
-nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext)
+nsTextControlFrame::nsTextControlFrame(nsStyleContext* aContext)
   : nsContainerFrame(aContext)
   , mEditorHasBeenInitialized(false)
   , mIsProcessing(false)
 #ifdef DEBUG
   , mInEditorInitialization(false)
 #endif
 {
 }
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -29,17 +29,17 @@ class nsTextControlFrame MOZ_FINAL : pub
                                      public nsITextControlFrame,
                                      public nsIStatefulFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   NS_DECLARE_FRAME_PROPERTY(ContentScrollPos, DestroyPoint)
 
-  nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+  explicit nsTextControlFrame(nsStyleContext* aContext);
   virtual ~nsTextControlFrame();
 
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
   virtual nsIScrollableFrame* GetScrollTargetFrame() MOZ_OVERRIDE {
     return do_QueryFrame(GetFirstPrincipalChild());
   }
 
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -5029,47 +5029,47 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
 
   // If we're inserting at the beginning of our list and we have an
   // inside bullet, insert after that bullet.
   if (!aPrevSibling && HasInsideBullet()) {
     aPrevSibling = GetInsideBullet();
   }
   
   // Attempt to find the line that contains the previous sibling
-  FrameLines* overflowLines;
   nsLineList* lineList = &mLines;
+  nsFrameList* frames = &mFrames;
   nsLineList::iterator prevSibLine = lineList->end();
   int32_t prevSiblingIndex = -1;
   if (aPrevSibling) {
     // XXX_perf This is technically O(N^2) in some cases, but by using
     // RFind instead of Find, we make it O(N) in the most common case,
     // which is appending content.
 
     // Find the line that contains the previous sibling
     if (!nsLineBox::RFindLineContaining(aPrevSibling, lineList->begin(),
                                         prevSibLine, mFrames.LastChild(),
                                         &prevSiblingIndex)) {
       // Not in mLines - try overflow lines.
-      overflowLines = GetOverflowLines();
-      lineList = overflowLines ? &overflowLines->mLines : nullptr;
+      FrameLines* overflowLines = GetOverflowLines();
+      bool found = false;
       if (overflowLines) {
         prevSibLine = overflowLines->mLines.end();
         prevSiblingIndex = -1;
-        if (!nsLineBox::RFindLineContaining(aPrevSibling, lineList->begin(),
-                                            prevSibLine,
-                                            overflowLines->mFrames.LastChild(),
-                                            &prevSiblingIndex)) {
-          lineList = nullptr;
-        }
+        found = nsLineBox::RFindLineContaining(aPrevSibling, lineList->begin(),
+                                               prevSibLine,
+                                               overflowLines->mFrames.LastChild(),
+                                               &prevSiblingIndex);
       }
-      if (!lineList) {
+      if (MOZ_LIKELY(found)) {
+        lineList = &overflowLines->mLines;
+        frames = &overflowLines->mFrames;
+      } else {
         // Note: defensive code! RFindLineContaining must not return
         // false in this case, so if it does...
         NS_NOTREACHED("prev sibling not in line list");
-        lineList = &mLines;
         aPrevSibling = nullptr;
         prevSibLine = lineList->end();
       }
     }
   }
 
   // Find the frame following aPrevSibling so that we can join up the
   // two lists of frames.
@@ -5090,19 +5090,18 @@ nsBlockFrame::AddFrames(nsFrameList& aFr
       line->MarkDirty();
       line->SetInvalidateTextRuns(true);
     }
   }
   else if (! lineList->empty()) {
     lineList->front()->MarkDirty();
     lineList->front()->SetInvalidateTextRuns(true);
   }
-  nsFrameList& frames = lineList == &mLines ? mFrames : overflowLines->mFrames;
   const nsFrameList::Slice& newFrames =
-    frames.InsertFrames(nullptr, aPrevSibling, aFrameList);
+    frames->InsertFrames(nullptr, aPrevSibling, aFrameList);
 
   // Walk through the new frames being added and update the line data
   // structures to fit.
   for (nsFrameList::Enumerator e(newFrames); !e.AtEnd(); e.Next()) {
     nsIFrame* newFrame = e.get();
     NS_ASSERTION(!aPrevSibling || aPrevSibling->GetNextSibling() == newFrame,
                  "Unexpected aPrevSibling");
     NS_ASSERTION(newFrame->GetType() != nsGkAtoms::placeholderFrame ||
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -82,22 +82,22 @@ BuildScrollContainerLayers()
 
 //----------------------------------------------------------------------
 
 //----------nsHTMLScrollFrame-------------------------------------------
 
 nsHTMLScrollFrame*
 NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot)
 {
-  return new (aPresShell) nsHTMLScrollFrame(aPresShell, aContext, aIsRoot);
+  return new (aPresShell) nsHTMLScrollFrame(aContext, aIsRoot);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsHTMLScrollFrame)
 
-nsHTMLScrollFrame::nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot)
+nsHTMLScrollFrame::nsHTMLScrollFrame(nsStyleContext* aContext, bool aIsRoot)
   : nsContainerFrame(aContext),
     mHelper(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
 }
 
 void
 nsHTMLScrollFrame::ScrollbarActivityStarted() const
 {
@@ -954,25 +954,25 @@ NS_QUERYFRAME_HEAD(nsHTMLScrollFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 //----------nsXULScrollFrame-------------------------------------------
 
 nsXULScrollFrame*
 NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
                      bool aIsRoot, bool aClipAllDescendants)
 {
-  return new (aPresShell) nsXULScrollFrame(aPresShell, aContext, aIsRoot,
+  return new (aPresShell) nsXULScrollFrame(aContext, aIsRoot,
                                            aClipAllDescendants);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsXULScrollFrame)
 
-nsXULScrollFrame::nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext,
+nsXULScrollFrame::nsXULScrollFrame(nsStyleContext* aContext,
                                    bool aIsRoot, bool aClipAllDescendants)
-  : nsBoxFrame(aShell, aContext, aIsRoot),
+  : nsBoxFrame(aContext, aIsRoot),
     mHelper(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
 {
   SetLayoutManager(nullptr);
   mHelper.mClipAllDescendants = aClipAllDescendants;
 }
 
 void
 nsXULScrollFrame::ScrollbarActivityStarted() const
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -808,17 +808,17 @@ public:
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 #ifdef ACCESSIBILITY
   virtual mozilla::a11y::AccType AccessibleType() MOZ_OVERRIDE;
 #endif
 
 protected:
-  nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot);
+  nsHTMLScrollFrame(nsStyleContext* aContext, bool aIsRoot);
   void SetSuppressScrollbarUpdate(bool aSuppress) {
     mHelper.mSupppressScrollbarUpdate = aSuppress;
   }
   bool GuessHScrollbarNeeded(const ScrollReflowState& aState);
   bool GuessVScrollbarNeeded(const ScrollReflowState& aState);
 
   bool IsScrollbarUpdateSuppressed() const {
     return mHelper.mSupppressScrollbarUpdate;
@@ -1170,17 +1170,17 @@ public:
   virtual void ScrollbarActivityStarted() const MOZ_OVERRIDE;
   virtual void ScrollbarActivityStopped() const MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 protected:
-  nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot,
+  nsXULScrollFrame(nsStyleContext* aContext, bool aIsRoot,
                    bool aClipAllDescendants);
 
   void ClampAndSetBounds(nsBoxLayoutState& aState, 
                          nsRect& aRect,
                          nsPoint aScrollPosition,
                          bool aRemoveOverflowAreas = false) {
     /* 
      * For RTL frames, restore the original scrolled position of the right
--- a/layout/generic/nsViewportFrame.cpp
+++ b/layout/generic/nsViewportFrame.cpp
@@ -231,44 +231,42 @@ ViewportFrame::Reflow(nsPresContext*    
                       // Being flowed initially at an unconstrained block size
                       // means we should return our child's intrinsic size.
                       aReflowState.ComputedBSize() != NS_UNCONSTRAINEDSIZE
                         ? aReflowState.ComputedBSize()
                         : kidBSize);
   aDesiredSize.SetSize(wm, maxSize);
   aDesiredSize.SetOverflowAreasToDesiredBounds();
 
-  if (IsAbsoluteContainer()) {
+  if (HasAbsolutelyPositionedChildren()) {
     // Make a copy of the reflow state and change the computed width and height
     // to reflect the available space for the fixed items
     nsHTMLReflowState reflowState(aReflowState);
 
     if (reflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
       // We have an intrinsic-height document with abs-pos/fixed-pos children.
       // Set the available height and mComputedHeight to our chosen height.
       reflowState.AvailableBSize() = maxSize.BSize(wm);
       // Not having border/padding simplifies things
       NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0,0,0,0),
                    "Viewports can't have border/padding");
       reflowState.SetComputedBSize(maxSize.BSize(wm));
     }
 
     nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState);
-
-    // Just reflow all the fixed-pos frames.
+    nsOverflowAreas* overflowAreas = &aDesiredSize.mOverflowAreas;
+    nsIScrollableFrame* rootScrollFrame =
+                    aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
+    if (rootScrollFrame && !rootScrollFrame->IsIgnoringViewportClipping()) {
+      overflowAreas = nullptr;
+    }
     GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
                                          rect,
                                          false, true, true, // XXX could be optimized
-                                         &aDesiredSize.mOverflowAreas);
-
-    nsIScrollableFrame* rootScrollFrame =
-                    aPresContext->PresShell()->GetRootScrollFrameAsScrollable();
-    if (rootScrollFrame && !rootScrollFrame->IsIgnoringViewportClipping()) {
-      aDesiredSize.SetOverflowAreasToDesiredBounds();
-    }
+                                         overflowAreas);
   }
 
   if (mFrames.NotEmpty()) {
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
   }
 
   // If we were dirty then do a repaint
   if (GetStateBits() & NS_FRAME_IS_DIRTY) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1103258-1-ref.html
@@ -0,0 +1,13 @@
+<style>
+#d1 {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  will-change: transform;
+  width: 64px;
+  height: 64px;
+  background: red;
+}
+</style>
+<div id="d1">
+</div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1103258-1.html
@@ -0,0 +1,37 @@
+<style>
+#d1 {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  will-change: transform;
+  width: 64px;
+  height: 64px;
+  background: red;
+}
+#d2 {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  will-change: opacity;
+  opacity: 0.5;
+  width: 32px;
+  height: 32px;
+  background:blue;
+}
+#d3 {
+  will-change: transform;
+}
+#d4 {
+  will-change: transform;
+}
+</style>
+<div id="d2">
+  <div id="d3">
+    sadf
+  </div>
+  <div id="d4">
+    sdf
+  </div>
+</div>
+<div id="d1">
+</div>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1844,10 +1844,11 @@ test-pref(layout.css.grid.enabled,true) 
 fails-if(Android) == 1062792-1.html 1062792-1-ref.html
 == 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
 test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html
 == 1069716-1.html 1069716-1-ref.html
 == 1078262-1.html about:blank
 test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
 fuzzy-if(winWidget&&!layersGPUAccelerated,1,31) fuzzy-if(B2G,128,75) == 1081185-1.html 1081185-1-ref.html   # fuzzy with event-regions, see bug 1107843
 == 1097437-1.html 1097437-1-ref.html
+== 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test
 == 1105137-1.html 1105137-1-ref.html
 fuzzy-if(d2d,36,304) HTTP(..) == 1116480-1-fakeitalic-overflow.html 1116480-1-fakeitalic-overflow-ref.html
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -491,17 +491,16 @@ CSS_KEY(smooth, smooth)
 CSS_KEY(soft, soft)
 CSS_KEY(soft-light, soft_light)
 CSS_KEY(solid, solid)
 CSS_KEY(space-around, space_around)
 CSS_KEY(space-between, space_between)
 CSS_KEY(span, span)
 CSS_KEY(spell-out, spell_out)
 CSS_KEY(square, square)
-CSS_KEY(stack, stack)
 CSS_KEY(stacked-fractions, stacked_fractions)
 CSS_KEY(start, start)
 CSS_KEY(static, static)
 CSS_KEY(status-bar, status_bar)
 CSS_KEY(step-end, step_end)
 CSS_KEY(step-start, step_start)
 CSS_KEY(sticky, sticky)
 CSS_KEY(stretch, stretch)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -7642,33 +7642,26 @@ CSSParserImpl::ParseGridAutoFlow()
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT, nullptr)) {
     AppendValue(eCSSProperty_grid_auto_flow, value);
     return true;
   }
 
   static const int32_t mask[] = {
     NS_STYLE_GRID_AUTO_FLOW_ROW | NS_STYLE_GRID_AUTO_FLOW_COLUMN,
-    NS_STYLE_GRID_AUTO_FLOW_DENSE | NS_STYLE_GRID_AUTO_FLOW_STACK,
     MASK_END_VALUE
   };
   if (!ParseBitmaskValues(value, nsCSSProps::kGridAutoFlowKTable, mask)) {
     return false;
   }
   int32_t bitField = value.GetIntValue();
 
-  // Requires one of these
-  if (!(bitField & NS_STYLE_GRID_AUTO_FLOW_ROW ||
-        bitField & NS_STYLE_GRID_AUTO_FLOW_COLUMN ||
-        bitField & NS_STYLE_GRID_AUTO_FLOW_STACK)) {
-    return false;
-  }
-
-  // 'stack' without 'row' or 'column' defaults to 'stack row'
-  if (bitField == NS_STYLE_GRID_AUTO_FLOW_STACK) {
+  // If neither row nor column is provided, row is assumed.
+  if (!(bitField & (NS_STYLE_GRID_AUTO_FLOW_ROW |
+                    NS_STYLE_GRID_AUTO_FLOW_COLUMN))) {
     value.SetIntValue(bitField | NS_STYLE_GRID_AUTO_FLOW_ROW,
                       eCSSUnit_Enumerated);
   }
 
   AppendValue(eCSSProperty_grid_auto_flow, value);
   return true;
 }
 
@@ -8521,21 +8514,20 @@ CSSParserImpl::ParseGrid()
   }
 
   // An empty value is always invalid.
   if (!GetToken(true)) {
     return false;
   }
 
   // The values starts with a <'grid-auto-flow'> if and only if
-  // it starts with a 'stack', 'dense', 'column' or 'row' keyword.
+  // it starts with a 'dense', 'column' or 'row' keyword.
   if (mToken.mType == eCSSToken_Ident) {
     nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent);
-    if (keyword == eCSSKeyword_stack ||
-        keyword == eCSSKeyword_dense ||
+    if (keyword == eCSSKeyword_dense ||
         keyword == eCSSKeyword_column ||
         keyword == eCSSKeyword_row) {
       UngetToken();
       return ParseGridAutoFlow() && ParseGridShorthandAutoProps();
     }
   }
   UngetToken();
 
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1353,17 +1353,16 @@ const KTableValue nsCSSProps::kFontWeigh
   eCSSKeyword_normal, NS_STYLE_FONT_WEIGHT_NORMAL,
   eCSSKeyword_bold, NS_STYLE_FONT_WEIGHT_BOLD,
   eCSSKeyword_bolder, NS_STYLE_FONT_WEIGHT_BOLDER,
   eCSSKeyword_lighter, NS_STYLE_FONT_WEIGHT_LIGHTER,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kGridAutoFlowKTable[] = {
-  eCSSKeyword_stack, NS_STYLE_GRID_AUTO_FLOW_STACK,
   eCSSKeyword_row, NS_STYLE_GRID_AUTO_FLOW_ROW,
   eCSSKeyword_column, NS_STYLE_GRID_AUTO_FLOW_COLUMN,
   eCSSKeyword_dense, NS_STYLE_GRID_AUTO_FLOW_DENSE,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kGridTrackBreadthKTable[] = {
   eCSSKeyword_min_content, NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -1259,17 +1259,17 @@ nsCSSValue::AppendToString(nsCSSProperty
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
                                          NS_FONT_VARIANT_NUMERIC_LINING,
                                          NS_FONT_VARIANT_NUMERIC_ORDINAL,
                                          aResult);
       break;
 
     case eCSSProperty_grid_auto_flow:
       nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
-                                         NS_STYLE_GRID_AUTO_FLOW_STACK,
+                                         NS_STYLE_GRID_AUTO_FLOW_ROW,
                                          NS_STYLE_GRID_AUTO_FLOW_DENSE,
                                          aResult);
       break;
 
     case eCSSProperty_grid_column_start:
     case eCSSProperty_grid_column_end:
     case eCSSProperty_grid_row_start:
     case eCSSProperty_grid_row_end:
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2365,17 +2365,17 @@ nsComputedDOMStyle::GetGridTemplateColum
 }
 
 CSSValue*
 nsComputedDOMStyle::DoGetGridAutoFlow()
 {
   nsAutoString str;
   nsStyleUtil::AppendBitmaskCSSValue(eCSSProperty_grid_auto_flow,
                                      StylePosition()->mGridAutoFlow,
-                                     NS_STYLE_GRID_AUTO_FLOW_STACK,
+                                     NS_STYLE_GRID_AUTO_FLOW_ROW,
                                      NS_STYLE_GRID_AUTO_FLOW_DENSE,
                                      str);
   nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
   val->SetString(str);
   return val;
 }
 
 CSSValue*
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -569,20 +569,19 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_FONT_INFO                      11
 #define NS_STYLE_FONT_DIALOG                    12
 #define NS_STYLE_FONT_BUTTON                    13
 #define NS_STYLE_FONT_PULL_DOWN_MENU            14
 #define NS_STYLE_FONT_LIST                      15
 #define NS_STYLE_FONT_FIELD                     16
 
 // grid-auto-flow keywords
-#define NS_STYLE_GRID_AUTO_FLOW_STACK           (1 << 0)
-#define NS_STYLE_GRID_AUTO_FLOW_ROW             (1 << 1)
-#define NS_STYLE_GRID_AUTO_FLOW_COLUMN          (1 << 2)
-#define NS_STYLE_GRID_AUTO_FLOW_DENSE           (1 << 3)
+#define NS_STYLE_GRID_AUTO_FLOW_ROW             (1 << 0)
+#define NS_STYLE_GRID_AUTO_FLOW_COLUMN          (1 << 1)
+#define NS_STYLE_GRID_AUTO_FLOW_DENSE           (1 << 2)
 
 // 'subgrid' keyword in grid-template-{columns,rows}
 #define NS_STYLE_GRID_TEMPLATE_SUBGRID          0
 
 // CSS Grid <track-breadth> keywords
 // Should not overlap with NS_STYLE_GRID_TEMPLATE_SUBGRID
 #define NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT 1
 #define NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT 2
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -447,16 +447,17 @@ nsTransitionManager::ConsiderStartingTra
     if (haveCurrentTransition) {
       // We're in the middle of a transition, and just got a non-transition
       // style change to something that we can't animate.  This might happen
       // because we got a non-transition style change changing to the current
       // in-progress value (which is particularly easy to cause when we're
       // currently in the 'transition-delay').  It also might happen because we
       // just got a style change to a value that can't be interpolated.
       AnimationPlayerPtrArray& players = aElementTransitions->mPlayers;
+      players[currentIndex]->Cancel();
       oldPT = nullptr; // Clear pointer so it doesn't dangle
       players.RemoveElementAt(currentIndex);
       aElementTransitions->UpdateAnimationGeneration(mPresContext);
 
       if (players.IsEmpty()) {
         aElementTransitions->Destroy();
         // |aElementTransitions| is now a dangling pointer!
         aElementTransitions = nullptr;
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -5072,29 +5072,23 @@ if (SpecialPowers.getBoolPref("layout.cs
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "row" ],
     other_values: [
       "column",
       "column dense",
       "row dense",
       "dense column",
       "dense row",
-      "stack column",
-      "stack row",
-      "stack",
+      "dense",
     ],
     invalid_values: [
       "",
       "auto",
       "none",
       "10px",
-      "dense",
-      "stack dense",
-      "stack stack",
-      "stack row stack",
       "column row",
       "dense row dense",
     ]
   };
 
   gCSSProperties["grid-auto-columns"] = {
     domProp: "gridAutoColumns",
     inherited: false,
@@ -5315,17 +5309,17 @@ if (SpecialPowers.getBoolPref("layout.cs
       "grid-auto-columns",
       "grid-auto-rows",
     ],
     initial_values: [
       "none",
       "none / none",
     ],
     other_values: [
-      "stack 40px",
+      "column 40px",
       "column dense auto",
       "dense row minmax(min-content, 2fr)",
       "row 40px / 100px",
     ].concat(
       gCSSProperties["grid-template"].other_values,
       gCSSProperties["grid-auto-flow"].other_values
     ),
     invalid_values: [
--- a/layout/style/test/test_grid_container_shorthands.html
+++ b/layout/style/test/test_grid_container_shorthands.html
@@ -174,23 +174,27 @@ var grid_template_test_cases = [
 ];
 
 grid_test_cases = grid_template_test_cases.concat([
     {
         specified: "row",
         gridAutoFlow: "row",
     },
     {
-        specified: "stack 40px",
-        gridAutoFlow: "stack row",
+        specified: "dense",
+        gridAutoFlow: "row dense",
+    },
+    {
+        specified: "row 40px",
+        gridAutoFlow: "row",
         gridAutoColumns: "40px",
     },
     {
-        specified: "stack column 40px",
-        gridAutoFlow: "stack column",
+        specified: "column 40px",
+        gridAutoFlow: "column",
         gridAutoColumns: "40px",
     },
     {
         specified: "column dense auto",
         gridAutoFlow: "column dense",
         gridAutoColumns: "minmax(min-content, max-content)",
     },
     {
--- a/layout/xul/grid/nsGridRowGroupFrame.cpp
+++ b/layout/xul/grid/nsGridRowGroupFrame.cpp
@@ -18,17 +18,17 @@
 
 already_AddRefed<nsBoxLayout> NS_NewGridRowGroupLayout();
 
 nsIFrame*
 NS_NewGridRowGroupFrame(nsIPresShell* aPresShell,
                         nsStyleContext* aContext)
 {
   nsCOMPtr<nsBoxLayout> layout = NS_NewGridRowGroupLayout();
-  return new (aPresShell) nsGridRowGroupFrame(aPresShell, aContext, layout);
+  return new (aPresShell) nsGridRowGroupFrame(aContext, layout);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGridRowGroupFrame)
 
 
 /**
  * This is redefined because row groups have a funny property. If they are flexible
  * then their flex must be equal to the sum of their children's flexes.
--- a/layout/xul/grid/nsGridRowGroupFrame.h
+++ b/layout/xul/grid/nsGridRowGroupFrame.h
@@ -30,20 +30,19 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
   {
       return MakeFrameName(NS_LITERAL_STRING("nsGridRowGroup"), aResult);
   }
 #endif
 
-  nsGridRowGroupFrame(nsIPresShell* aPresShell,
-                      nsStyleContext* aContext,
+  nsGridRowGroupFrame(nsStyleContext* aContext,
                       nsBoxLayout* aLayoutManager):
-    nsBoxFrame(aPresShell, aContext, false, aLayoutManager) {}
+    nsBoxFrame(aContext, false, aLayoutManager) {}
 
   virtual nscoord GetFlex(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
 
 }; // class nsGridRowGroupFrame
 
 
 
 #endif
--- a/layout/xul/grid/nsGridRowLeafFrame.cpp
+++ b/layout/xul/grid/nsGridRowLeafFrame.cpp
@@ -18,18 +18,17 @@
 
 already_AddRefed<nsBoxLayout> NS_NewGridRowLeafLayout();
 
 nsIFrame*
 NS_NewGridRowLeafFrame(nsIPresShell* aPresShell,
                        nsStyleContext* aContext)
 {
   nsCOMPtr<nsBoxLayout> layout = NS_NewGridRowLeafLayout();
-  return new (aPresShell) nsGridRowLeafFrame(aPresShell, aContext, false,
-                                             layout);
+  return new (aPresShell) nsGridRowLeafFrame(aContext, false, layout);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGridRowLeafFrame)
 
 /*
  * Our border and padding could be affected by our columns or rows.
  * Let's go check it out.
  */
--- a/layout/xul/grid/nsGridRowLeafFrame.h
+++ b/layout/xul/grid/nsGridRowLeafFrame.h
@@ -34,21 +34,20 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
   {
       return MakeFrameName(NS_LITERAL_STRING("nsGridRowLeaf"), aResult);
   }
 #endif
 
-  nsGridRowLeafFrame(nsIPresShell* aPresShell,
-                     nsStyleContext* aContext,
+  nsGridRowLeafFrame(nsStyleContext* aContext,
                      bool aIsRoot,
                      nsBoxLayout* aLayoutManager):
-    nsBoxFrame(aPresShell, aContext, aIsRoot, aLayoutManager) {}
+    nsBoxFrame(aContext, aIsRoot, aLayoutManager) {}
 
   virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding) MOZ_OVERRIDE;
 
 }; // class nsGridRowLeafFrame
 
 
 
 #endif
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -92,35 +92,34 @@ using namespace mozilla::gfx;
 #ifdef DEBUG_LAYOUT
 bool nsBoxFrame::gDebug = false;
 nsIFrame* nsBoxFrame::mDebugChild = nullptr;
 #endif
 
 nsIFrame*
 NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager)
 {
-  return new (aPresShell) nsBoxFrame(aPresShell, aContext, aIsRoot, aLayoutManager);
+  return new (aPresShell) nsBoxFrame(aContext, aIsRoot, aLayoutManager);
 }
 
 nsIFrame*
 NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsBoxFrame(aPresShell, aContext);
+  return new (aPresShell) nsBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
 
 #ifdef DEBUG
 NS_QUERYFRAME_HEAD(nsBoxFrame)
   NS_QUERYFRAME_ENTRY(nsBoxFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 #endif
 
-nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell,
-                       nsStyleContext* aContext,
+nsBoxFrame::nsBoxFrame(nsStyleContext* aContext,
                        bool aIsRoot,
                        nsBoxLayout* aLayoutManager) :
   nsContainerFrame(aContext)
 {
   mState |= NS_STATE_IS_HORIZONTAL;
   mState |= NS_STATE_AUTO_STRETCH;
 
   if (aIsRoot) 
@@ -128,17 +127,17 @@ nsBoxFrame::nsBoxFrame(nsIPresShell* aPr
 
   mValign = vAlign_Top;
   mHalign = hAlign_Left;
   
   // if no layout manager specified us the static sprocket layout
   nsCOMPtr<nsBoxLayout> layout = aLayoutManager;
 
   if (layout == nullptr) {
-    NS_NewSprocketLayout(aPresShell, layout);
+    NS_NewSprocketLayout(PresContext()->PresShell(), layout);
   }
 
   SetLayoutManager(layout);
 }
 
 nsBoxFrame::~nsBoxFrame()
 {
 }
--- a/layout/xul/nsBoxFrame.h
+++ b/layout/xul/nsBoxFrame.h
@@ -138,17 +138,17 @@ public:
   virtual void DidReflow(nsPresContext*           aPresContext,
                          const nsHTMLReflowState* aReflowState,
                          nsDidReflowStatus        aStatus) MOZ_OVERRIDE;
 
   virtual bool HonorPrintBackgroundSettings() MOZ_OVERRIDE;
 
   virtual ~nsBoxFrame();
   
-  nsBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot = false, nsBoxLayout* aLayoutManager = nullptr);
+  explicit nsBoxFrame(nsStyleContext* aContext, bool aIsRoot = false, nsBoxLayout* aLayoutManager = nullptr);
 
   // virtual so nsStackFrame, nsButtonBoxFrame, nsSliderFrame and nsMenuFrame
   // can override it
   virtual void BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                            const nsRect&           aDirtyRect,
                                            const nsDisplayListSet& aLists);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
--- a/layout/xul/nsButtonBoxFrame.cpp
+++ b/layout/xul/nsButtonBoxFrame.cpp
@@ -25,17 +25,17 @@ using namespace mozilla;
 //
 // NS_NewXULButtonFrame
 //
 // Creates a new Button frame and returns it
 //
 nsIFrame*
 NS_NewButtonBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsButtonBoxFrame(aPresShell, aContext);
+  return new (aPresShell) nsButtonBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame)
 
 void
 nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                               const nsRect&           aDirtyRect,
                                               const nsDisplayListSet& aLists)
--- a/layout/xul/nsButtonBoxFrame.h
+++ b/layout/xul/nsButtonBoxFrame.h
@@ -10,18 +10,18 @@
 
 class nsButtonBoxFrame : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
   friend nsIFrame* NS_NewButtonBoxFrame(nsIPresShell* aPresShell);
 
-  nsButtonBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-    :nsBoxFrame(aPresShell, aContext, false) {
+  explicit nsButtonBoxFrame(nsStyleContext* aContext)
+    :nsBoxFrame(aContext, false) {
     UpdateMouseThrough();
   }
 
   virtual void BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                            const nsRect&           aDirtyRect,
                                            const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual nsresult HandleEvent(nsPresContext* aPresContext, 
--- a/layout/xul/nsDeckFrame.cpp
+++ b/layout/xul/nsDeckFrame.cpp
@@ -29,31 +29,31 @@
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 nsIFrame*
 NS_NewDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsDeckFrame(aPresShell, aContext);
+  return new (aPresShell) nsDeckFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame)
 
 NS_QUERYFRAME_HEAD(nsDeckFrame)
   NS_QUERYFRAME_ENTRY(nsDeckFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
 
 
-nsDeckFrame::nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-  : nsBoxFrame(aPresShell, aContext), mIndex(0)
+nsDeckFrame::nsDeckFrame(nsStyleContext* aContext)
+  : nsBoxFrame(aContext), mIndex(0)
 {
   nsCOMPtr<nsBoxLayout> layout;
-  NS_NewStackLayout(aPresShell, layout);
+  NS_NewStackLayout(PresContext()->PresShell(), layout);
   SetLayoutManager(layout);
 }
 
 nsIAtom*
 nsDeckFrame::GetType() const
 {
   return nsGkAtoms::deckFrame;
 }
--- a/layout/xul/nsDeckFrame.h
+++ b/layout/xul/nsDeckFrame.h
@@ -52,17 +52,17 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE
   {
       return MakeFrameName(NS_LITERAL_STRING("Deck"), aResult);
   }
 #endif
 
-  nsDeckFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+  explicit nsDeckFrame(nsStyleContext* aContext);
 
   nsIFrame* GetSelectedBox();
 
 protected:
 
   void IndexChanged();
   int32_t GetSelectedIndex();
   void HideBox(nsIFrame* aBox);
--- a/layout/xul/nsDocElementBoxFrame.cpp
+++ b/layout/xul/nsDocElementBoxFrame.cpp
@@ -30,18 +30,18 @@ class nsDocElementBoxFrame : public nsBo
                              public nsIAnonymousContentCreator
 {
 public:
   virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
 
   friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
-  nsDocElementBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext)
-    :nsBoxFrame(aShell, aContext, true) {}
+  explicit nsDocElementBoxFrame(nsStyleContext* aContext)
+    :nsBoxFrame(aContext, true) {}
 
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // nsIAnonymousContentCreator
   virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) MOZ_OVERRIDE;
   virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
                                         uint32_t aFilter) MOZ_OVERRIDE;
@@ -62,17 +62,17 @@ private:
   nsCOMPtr<Element> mTooltipContent;
 };
 
 //----------------------------------------------------------------------
 
 nsContainerFrame*
 NS_NewDocElementBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsDocElementBoxFrame (aPresShell, aContext);
+  return new (aPresShell) nsDocElementBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsDocElementBoxFrame)
 
 void
 nsDocElementBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsContentUtils::DestroyAnonymousContent(&mPopupgroupContent);
--- a/layout/xul/nsGroupBoxFrame.cpp
+++ b/layout/xul/nsGroupBoxFrame.cpp
@@ -16,18 +16,18 @@
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 class nsGroupBoxFrame : public nsBoxFrame {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
-  nsGroupBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
-    nsBoxFrame(aShell, aContext) {}
+  explicit nsGroupBoxFrame(nsStyleContext* aContext):
+    nsBoxFrame(aContext) {}
 
   virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding);
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
@@ -70,17 +70,17 @@ public:
   virtual bool GetDefaultFlex(int32_t& aFlex) { aFlex = 1; return true; }
 
 };
 */
 
 nsIFrame*
 NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsGroupBoxFrame(aPresShell, aContext);
+  return new (aPresShell) nsGroupBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
 
 class nsDisplayXULGroupBackground : public nsDisplayItem {
 public:
   nsDisplayXULGroupBackground(nsDisplayListBuilder* aBuilder,
                               nsGroupBoxFrame* aFrame) :
--- a/layout/xul/nsImageBoxFrame.cpp
+++ b/layout/xul/nsImageBoxFrame.cpp
@@ -114,17 +114,17 @@ FireImageDOMEvent(nsIContent* aContent, 
 //
 // NS_NewImageBoxFrame
 //
 // Creates a new image frame and returns it
 //
 nsIFrame*
 NS_NewImageBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsImageBoxFrame (aPresShell, aContext);
+  return new (aPresShell) nsImageBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsImageBoxFrame)
 
 nsresult
 nsImageBoxFrame::AttributeChanged(int32_t aNameSpaceID,
                                   nsIAtom* aAttribute,
                                   int32_t aModType)
@@ -138,18 +138,18 @@ nsImageBoxFrame::AttributeChanged(int32_
       FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
   }
   else if (aAttribute == nsGkAtoms::validate)
     UpdateLoadFlags();
 
   return rv;
 }
 
-nsImageBoxFrame::nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
-  nsLeafBoxFrame(aShell, aContext),
+nsImageBoxFrame::nsImageBoxFrame(nsStyleContext* aContext):
+  nsLeafBoxFrame(aContext),
   mIntrinsicSize(0,0),
   mRequestRegistered(false),
   mLoadFlags(nsIRequest::LOAD_NORMAL),
   mUseSrcAttr(false),
   mSuppressStyleCheck(false),
   mFireEventOnDecode(false)
 {
   MarkIntrinsicISizesDirty();
--- a/layout/xul/nsImageBoxFrame.h
+++ b/layout/xul/nsImageBoxFrame.h
@@ -91,17 +91,17 @@ public:
   virtual ~nsImageBoxFrame();
 
   void  PaintImage(nsRenderingContext& aRenderingContext,
                    const nsRect& aDirtyRect,
                    nsPoint aPt, uint32_t aFlags);
 
   already_AddRefed<mozilla::layers::ImageContainer> GetContainer(LayerManager* aManager);
 protected:
-  nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+  explicit nsImageBoxFrame(nsStyleContext* aContext);
 
   virtual void GetImageSize();
 
 private:
   nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
   nsresult OnDecodeComplete(imgIRequest* aRequest);
   nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
   nsresult OnImageIsAnimated(imgIRequest* aRequest);
--- a/layout/xul/nsLeafBoxFrame.cpp
+++ b/layout/xul/nsLeafBoxFrame.cpp
@@ -30,22 +30,22 @@ using namespace mozilla;
 //
 // NS_NewLeafBoxFrame
 //
 // Creates a new Toolbar frame and returns it
 //
 nsIFrame*
 NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsLeafBoxFrame(aPresShell, aContext);
+  return new (aPresShell) nsLeafBoxFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame)
 
-nsLeafBoxFrame::nsLeafBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext)
+nsLeafBoxFrame::nsLeafBoxFrame(nsStyleContext* aContext)
     : nsLeafFrame(aContext)
 {
 }
 
 #ifdef DEBUG_LAYOUT
 void
 nsLeafBoxFrame::GetBoxName(nsAutoString& aName)
 {
--- a/layout/xul/nsLeafBoxFrame.h
+++ b/layout/xul/nsLeafBoxFrame.h
@@ -80,17 +80,17 @@ protected:
   NS_IMETHOD DoLayout(nsBoxLayoutState& aState) MOZ_OVERRIDE;
 
 #ifdef DEBUG_LAYOUT
   virtual void GetBoxName(nsAutoString& aName) MOZ_OVERRIDE;
 #endif
 
   virtual nscoord GetIntrinsicISize() MOZ_OVERRIDE;
 
- nsLeafBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+ explicit nsLeafBoxFrame(nsStyleContext* aContext);
 
 private:
 
  void UpdateMouseThrough();
 
 
 }; // class nsLeafBoxFrame
 
--- a/layout/xul/nsListBoxBodyFrame.cpp
+++ b/layout/xul/nsListBoxBodyFrame.cpp
@@ -134,20 +134,19 @@ nsListScrollSmoother::Stop()
     mRepeatTimer = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS(nsListScrollSmoother, nsITimerCallback)
 
 /////////////// nsListBoxBodyFrame //////////////////
 
-nsListBoxBodyFrame::nsListBoxBodyFrame(nsIPresShell* aPresShell,
-                                       nsStyleContext* aContext,
+nsListBoxBodyFrame::nsListBoxBodyFrame(nsStyleContext* aContext,
                                        nsBoxLayout* aLayoutManager)
-  : nsBoxFrame(aPresShell, aContext, false, aLayoutManager),
+  : nsBoxFrame(aContext, false, aLayoutManager),
     mTopFrame(nullptr),
     mBottomFrame(nullptr),
     mLinkupFrame(nullptr),
     mScrollSmoother(nullptr),
     mRowsToPrepend(0),
     mRowCount(-1),
     mRowHeight(0),
     mAvailableHeight(0),
@@ -1521,12 +1520,12 @@ nsListBoxBodyFrame::RemoveChildFrame(nsB
 // Creation Routines ///////////////////////////////////////////////////////////////////////
 
 already_AddRefed<nsBoxLayout> NS_NewListBoxLayout();
 
 nsIFrame*
 NS_NewListBoxBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   nsCOMPtr<nsBoxLayout> layout = NS_NewListBoxLayout();
-  return new (aPresShell) nsListBoxBodyFrame(aPresShell, aContext, layout);
+  return new (aPresShell) nsListBoxBodyFrame(aContext, layout);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsListBoxBodyFrame)
--- a/layout/xul/nsListBoxBodyFrame.h
+++ b/layout/xul/nsListBoxBodyFrame.h
@@ -19,17 +19,17 @@ class nsPresContext;
 class nsListScrollSmoother;
 nsIFrame* NS_NewListBoxBodyFrame(nsIPresShell* aPresShell,
                                  nsStyleContext* aContext);
 
 class nsListBoxBodyFrame MOZ_FINAL : public nsBoxFrame,
                                      public nsIScrollbarMediator,
                                      public nsIReflowCallback
 {
-  nsListBoxBodyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext,
+  nsListBoxBodyFrame(nsStyleContext* aContext,
                      nsBoxLayout* aLayoutManager);
   virtual ~nsListBoxBodyFrame();
 
 public:
   NS_DECL_QUERYFRAME_TARGET(nsListBoxBodyFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
--- a/layout/xul/nsListItemFrame.cpp
+++ b/layout/xul/nsListItemFrame.cpp
@@ -9,21 +9,20 @@
 
 #include "nsCOMPtr.h"
 #include "nsNameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsDisplayList.h"
 #include "nsBoxLayout.h"
 #include "nsIContent.h"
 
-nsListItemFrame::nsListItemFrame(nsIPresShell* aPresShell,
-                                 nsStyleContext* aContext,
+nsListItemFrame::nsListItemFrame(nsStyleContext* aContext,
                                  bool aIsRoot,
                                  nsBoxLayout* aLayoutManager)
-  : nsGridRowLeafFrame(aPresShell, aContext, aIsRoot, aLayoutManager) 
+  : nsGridRowLeafFrame(aContext, aIsRoot, aLayoutManager) 
 {
 }
 
 nsListItemFrame::~nsListItemFrame()
 {
 }
 
 nsSize
@@ -59,12 +58,12 @@ already_AddRefed<nsBoxLayout> NS_NewGrid
 nsIFrame*
 NS_NewListItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   nsCOMPtr<nsBoxLayout> layout = NS_NewGridRowLeafLayout();
   if (!layout) {
     return nullptr;
   }
   
-  return new (aPresShell) nsListItemFrame(aPresShell, aContext, false, layout);
+  return new (aPresShell) nsListItemFrame(aContext, false, layout);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsListItemFrame)
--- a/layout/xul/nsListItemFrame.h
+++ b/layout/xul/nsListItemFrame.h
@@ -21,15 +21,14 @@ public:
   // unless allowevents="true" is specified on the listitem
   virtual void BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
                                            const nsRect&           aDirtyRect,
                                            const nsDisplayListSet& aLists) MOZ_OVERRIDE;
 
   virtual nsSize GetPrefSize(nsBoxLayoutState& aState) MOZ_OVERRIDE;
 
 protected:
-  nsListItemFrame(nsIPresShell* aPresShell,
-                  nsStyleContext *aContext,
-                  bool aIsRoot = false,
-                  nsBoxLayout* aLayoutManager = nullptr);
+  explicit nsListItemFrame(nsStyleContext *aContext,
+                           bool aIsRoot = false,
+                           nsBoxLayout* aLayoutManager = nullptr);
   virtual ~nsListItemFrame();
 
 }; // class nsListItemFrame
--- a/layout/xul/nsMenuBarFrame.cpp
+++ b/layout/xul/nsMenuBarFrame.cpp
@@ -32,30 +32,30 @@ using namespace mozilla;
 //
 // NS_NewMenuBarFrame
 //
 // Wrapper for creating a new menu Bar container
 //
 nsIFrame*
 NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsMenuBarFrame (aPresShell, aContext);
+  return new (aPresShell) nsMenuBarFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMenuBarFrame)
 
 NS_QUERYFRAME_HEAD(nsMenuBarFrame)
   NS_QUERYFRAME_ENTRY(nsMenuBarFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
 
 //
 // nsMenuBarFrame cntr
 //
-nsMenuBarFrame::nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext):
-  nsBoxFrame(aShell, aContext),
+nsMenuBarFrame::nsMenuBarFrame(nsStyleContext* aContext):
+  nsBoxFrame(aContext),
     mMenuBarListener(nullptr),
     mStayActive(false),
     mIsActive(false),
     mCurrentMenu(nullptr),
     mTarget(nullptr)
 {
 } // cntr
 
--- a/layout/xul/nsMenuBarFrame.h
+++ b/layout/xul/nsMenuBarFrame.h
@@ -24,17 +24,17 @@ nsIFrame* NS_NewMenuBarFrame(nsIPresShel
 
 class nsMenuBarFrame MOZ_FINAL : public nsBoxFrame, public nsMenuParent
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsMenuBarFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+  explicit nsMenuBarFrame(nsStyleContext* aContext);
 
   // nsMenuParent interface
   virtual nsMenuFrame* GetCurrentMenuItem() MOZ_OVERRIDE;
   NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) MOZ_OVERRIDE;
   virtual void CurrentMenuIsBeingDestroyed() MOZ_OVERRIDE;
   NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, bool aSelectFirstItem) MOZ_OVERRIDE;
 
   NS_IMETHOD SetActive(bool aActiveFlag) MOZ_OVERRIDE; 
--- a/layout/xul/nsMenuFrame.cpp
+++ b/layout/xul/nsMenuFrame.cpp
@@ -150,37 +150,37 @@ protected:
 //
 // NS_NewMenuFrame and NS_NewMenuItemFrame
 //
 // Wrappers for creating a new menu popup container
 //
 nsIFrame*
 NS_NewMenuFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  nsMenuFrame* it = new (aPresShell) nsMenuFrame (aPresShell, aContext);
+  nsMenuFrame* it = new (aPresShell) nsMenuFrame(aContext);
   it->SetIsMenu(true);
   return it;
 }
 
 nsIFrame*
 NS_NewMenuItemFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  nsMenuFrame* it = new (aPresShell) nsMenuFrame (aPresShell, aContext);
+  nsMenuFrame* it = new (aPresShell) nsMenuFrame(aContext);
   it->SetIsMenu(false);
   return it;
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMenuFrame)
 
 NS_QUERYFRAME_HEAD(nsMenuFrame)
   NS_QUERYFRAME_ENTRY(nsMenuFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
 
-nsMenuFrame::nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext):
-  nsBoxFrame(aShell, aContext),
+nsMenuFrame::nsMenuFrame(nsStyleContext* aContext):
+  nsBoxFrame(aContext),
     mIsMenu(false),
     mChecked(false),
     mIgnoreAccelTextChange(false),
     mType(eMenuType_Normal),
     mBlinkState(0)
 {
 }
 
--- a/layout/xul/nsMenuFrame.h
+++ b/layout/xul/nsMenuFrame.h
@@ -70,17 +70,17 @@ private:
 
   // Pointer to the wrapped frame.
   nsMenuFrame* mFrame;
 };
 
 class nsMenuFrame MOZ_FINAL : public nsBoxFrame
 {
 public:
-  nsMenuFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+  explicit nsMenuFrame(nsStyleContext* aContext);
 
   NS_DECL_QUERYFRAME_TARGET(nsMenuFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -62,30 +62,30 @@ int8_t nsMenuPopupFrame::sDefaultLevelIs
 
 // NS_NewMenuPopupFrame
 //
 // Wrapper for creating a new menu popup container
 //
 nsIFrame*
 NS_NewMenuPopupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsMenuPopupFrame (aPresShell, aContext);
+  return new (aPresShell) nsMenuPopupFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsMenuPopupFrame)
 
 NS_QUERYFRAME_HEAD(nsMenuPopupFrame)
   NS_QUERYFRAME_ENTRY(nsMenuPopupFrame)
 NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
 
 //
 // nsMenuPopupFrame ctor
 //
-nsMenuPopupFrame::nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext)
-  :nsBoxFrame(aShell, aContext),
+nsMenuPopupFrame::nsMenuPopupFrame(nsStyleContext* aContext)
+  :nsBoxFrame(aContext),
   mCurrentMenu(nullptr),
   mPrefSize(-1, -1),
   mLastClientOffset(0, 0),
   mPopupType(ePopupTypePanel),
   mPopupState(ePopupClosed),
   mPopupAlignment(POPUPALIGNMENT_NONE),
   mPopupAnchor(POPUPALIGNMENT_NONE),
   mPosition(POPUPPOSITION_UNKNOWN),
--- a/layout/xul/nsMenuPopupFrame.h
+++ b/layout/xul/nsMenuPopupFrame.h
@@ -150,17 +150,17 @@ private:
 
 class nsMenuPopupFrame MOZ_FINAL : public nsBoxFrame, public nsMenuParent
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsMenuPopupFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  nsMenuPopupFrame(nsIPresShell* aShell, nsStyleContext* aContext);
+  explicit nsMenuPopupFrame(nsStyleContext* aContext);
 
   // nsMenuParent interface
   virtual nsMenuFrame* GetCurrentMenuItem() MOZ_OVERRIDE;
   NS_IMETHOD SetCurrentMenuItem(nsMenuFrame* aMenuItem) MOZ_OVERRIDE;
   virtual void CurrentMenuIsBeingDestroyed() MOZ_OVERRIDE;
   NS_IMETHOD ChangeMenuItem(nsMenuFrame* aMenuItem, bool aSelectFirstItem) MOZ_OVERRIDE;
 
   // as popups are opened asynchronously, the popup pending state is used to
--- a/layout/xul/nsPopupSetFrame.cpp
+++ b/layout/xul/nsPopupSetFrame.cpp
@@ -12,17 +12,17 @@
 #include "nsBoxLayoutState.h"
 #include "nsIScrollableFrame.h"
 #include "nsIRootBox.h"
 #include "nsMenuPopupFrame.h"
 
 nsIFrame*
 NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsPopupSetFrame (aPresShell, aContext);
+  return new (aPresShell) nsPopupSetFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsPopupSetFrame)
 
 void
 nsPopupSetFrame::Init(nsIContent*       aContent,
                       nsContainerFrame* aParent,
                       nsIFrame*         aPrevInFlow)
--- a/layout/xul/nsPopupSetFrame.h
+++ b/layout/xul/nsPopupSetFrame.h
@@ -13,18 +13,18 @@
 
 nsIFrame* NS_NewPopupSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 class nsPopupSetFrame : public nsBoxFrame
 {
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
-  nsPopupSetFrame(nsIPresShell* aShell, nsStyleContext* aContext):
-    nsBoxFrame(aShell, aContext) {}
+  explicit nsPopupSetFrame(nsStyleContext* aContext):
+    nsBoxFrame(aContext) {}
 
   ~nsPopupSetFrame() {}
   
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
                     nsIFrame*         aPrevInFlow) MOZ_OVERRIDE;
 
   virtual void SetInitialChildList(ChildListID  aListID,
--- a/layout/xul/nsProgressMeterFrame.cpp
+++ b/layout/xul/nsProgressMeterFrame.cpp
@@ -58,17 +58,17 @@ nsReflowFrameRunnable::Run()
 //
 // NS_NewToolbarFrame
 //
 // Creates a new Toolbar frame and returns it
 //
 nsIFrame*
 NS_NewProgressMeterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsProgressMeterFrame(aPresShell, aContext);
+  return new (aPresShell) nsProgressMeterFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsProgressMeterFrame)
 
 //
 // nsProgressMeterFrame dstr
 //
 // Cleanup, if necessary
--- a/layout/xul/nsProgressMeterFrame.h
+++ b/layout/xul/nsProgressMeterFrame.h
@@ -33,14 +33,14 @@ public:
                                     nsIAtom* aAttribute,
                                     int32_t aModType) MOZ_OVERRIDE;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const MOZ_OVERRIDE;
 #endif
 
 protected:
-  nsProgressMeterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) :
-    nsBoxFrame(aPresShell, aContext), mNeedsReflowCallback(true) {}
+  explicit nsProgressMeterFrame(nsStyleContext* aContext) :
+    nsBoxFrame(aContext), mNeedsReflowCallback(true) {}
   virtual ~nsProgressMeterFrame();
 
   bool mNeedsReflowCallback;
 }; // class nsProgressMeterFrame
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -33,23 +33,23 @@ using namespace mozilla;
 //
 // NS_NewResizerFrame
 //
 // Creates a new Resizer frame and returns it
 //
 nsIFrame*
 NS_NewResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
-  return new (aPresShell) nsResizerFrame(aPresShell, aContext);
+  return new (aPresShell) nsResizerFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsResizerFrame)
 
-nsResizerFrame::nsResizerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-:nsTitleBarFrame(aPresShell, aContext)
+nsResizerFrame::nsResizerFrame(nsStyleContext* aContext)
+:nsTitleBarFrame(aContext)
 {
 }
 
 nsresult
 nsResizerFrame::HandleEvent(nsPresContext* aPresContext,
                             WidgetGUIEvent* aEvent,
                             nsEventStatus* aEventStatus)
 {
--- a/layout/xul/nsResizerFrame.h
+++ b/l