Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 26 Jan 2015 16:28:17 -0500
changeset 225838 a6f037b538edf7bf154129fe124e81b920eb805f
parent 225837 c3a90afa2deef9cca739d6b291269d713fbff98e (current diff)
parent 225693 8c25582fc7768c0bd5a03f56fe2dac0460a4d0a0 (diff)
child 225884 38e4719e71af140cb95f04f7165d43a34c35a30d
push id54672
push userryanvm@gmail.com
push dateMon, 26 Jan 2015 21:51:33 +0000
treeherdermozilla-inbound@c1cb74f492e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone38.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
layout/reftests/reftest-sanity/test-displayport.html
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -520,21 +520,18 @@ Accessible::FocusedChild()
 }
 
 Accessible*
 Accessible::ChildAtPoint(int32_t aX, int32_t aY,
                          EWhichChildAtPoint aWhichChild)
 {
   // If we can't find the point in a child, we will return the fallback answer:
   // we return |this| if the point is within it, otherwise nullptr.
+  Accessible* fallbackAnswer = nullptr;
   nsIntRect rect = Bounds();
-  if (rect.IsEmpty())
-   return nullptr;
-
-  Accessible* fallbackAnswer = nullptr;
   if (aX >= rect.x && aX < rect.x + rect.width &&
       aY >= rect.y && aY < rect.y + rect.height)
     fallbackAnswer = this;
 
   if (nsAccUtils::MustPrune(this))  // Do not dig any further
     return fallbackAnswer;
 
   // Search an accessible at the given point starting from accessible document
--- a/accessible/tests/mochitest/hittest/test_general.html
+++ b/accessible/tests/mochitest/hittest/test_general.html
@@ -63,16 +63,18 @@ if (!MAC) {
 
       testChildAtPoint("area", 1, 1, "area", "area");
 
       // Test image maps. Their children are not in the layout tree.
       var theLetterA = getAccessible("imgmap").firstChild;
       hitTest("imgmap", theLetterA, theLetterA);
       hitTest("container", "imgmap", theLetterA);
 
+      // hit testing for element contained by zero-width element
+      hitTest("container2", "container2_input", "container2_input");
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doPreTest);
   </script>
 </head>
 <body>
@@ -101,10 +103,13 @@ if (!MAC) {
     <area href="http://www.bbc.co.uk/radio4/atoz/index.shtml#a"
           coords="0,0,15,15" alt="thelettera" shape="rect"/>
   </map>
 
   <div id="container">
     <img id="imgmap" width="447" height="15" usemap="#atoz_map" src="../letters.gif"/>
   </div>
 
+  <div id="container2" style="width: 0px">
+    <input id="container2_input">
+  </div>
 </body>
 </html>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1181,17 +1181,17 @@ pref("browser.tabs.remote.desktopbehavio
 // process and also if they are subsequently allowed by the broker process.
 // This will require a restart.
 pref("security.sandbox.windows.log", false);
 
 // Controls whether the Windows NPAPI plugin process is sandboxed by default.
 // To get a different setting for a particular plugin replace "default", with
 // the plugin's nice file name, see: nsPluginTag::GetNiceFileName.
 pref("dom.ipc.plugins.sandbox.default", false);
-pref("dom.ipc.plugins.sandbox.flash", false);
+pref("dom.ipc.plugins.sandbox.flash", true);
 
 #if defined(MOZ_CONTENT_SANDBOX)
 // This controls whether the Windows content process sandbox is using a more
 // strict sandboxing policy.  This will require a restart.
 pref("security.sandbox.windows.content.moreStrict", false);
 
 #if defined(MOZ_STACKWALKING)
 // This controls the depth of stack trace that is logged when Windows sandbox
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -3378,20 +3378,18 @@ 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 (parentAsDocShell->GetIsPrerendered()) {
+          SetIsPrerendered(true);
         }
         if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
             value = false;
         }
         SetAllowDNSPrefetch(value);
         value = parentAsDocShell->GetAffectPrivateSessionLifetime();
         SetAffectPrivateSessionLifetime(value);
         uint32_t flags;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -619,17 +619,17 @@ interface nsIDocShell : nsIDocShellTreeI
    */
   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;
+  [infallible] 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
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -392,20 +392,20 @@ EventListenerManagerHashClearEntry(PLDHa
 {
   EventListenerManagerMapEntry *lm =
     static_cast<EventListenerManagerMapEntry *>(entry);
 
   // Let the EventListenerManagerMapEntry clean itself up...
   lm->~EventListenerManagerMapEntry();
 }
 
-class SameOriginChecker MOZ_FINAL : public nsIChannelEventSink,
-                                    public nsIInterfaceRequestor
-{
-  ~SameOriginChecker() {}
+class SameOriginCheckerImpl MOZ_FINAL : public nsIChannelEventSink,
+                                        public nsIInterfaceRequestor
+{
+  ~SameOriginCheckerImpl() {}
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
 };
 
 class CharsetDetectionObserver MOZ_FINAL : public nsICharsetDetectionObserver
 {
@@ -5643,21 +5643,21 @@ nsContentUtils::StringContainsASCIIUpper
     ++iter;
   }
 
   return false;
 }
 
 /* static */
 nsIInterfaceRequestor*
-nsContentUtils::GetSameOriginChecker()
+nsContentUtils::SameOriginChecker()
 {
   if (!sSameOriginChecker) {
-    sSameOriginChecker = new SameOriginChecker();
-    NS_IF_ADDREF(sSameOriginChecker);
+    sSameOriginChecker = new SameOriginCheckerImpl();
+    NS_ADDREF(sSameOriginChecker);
   }
   return sSameOriginChecker;
 }
 
 /* static */
 nsresult
 nsContentUtils::CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel)
 {
@@ -5678,38 +5678,38 @@ nsContentUtils::CheckSameOrigin(nsIChann
   nsresult rv = oldPrincipal->CheckMayLoad(newURI, false, false);
   if (NS_SUCCEEDED(rv) && newOriginalURI != newURI) {
     rv = oldPrincipal->CheckMayLoad(newOriginalURI, false, false);
   }
 
   return rv;
 }
 
-NS_IMPL_ISUPPORTS(SameOriginChecker,
+NS_IMPL_ISUPPORTS(SameOriginCheckerImpl,
                   nsIChannelEventSink,
                   nsIInterfaceRequestor)
 
 NS_IMETHODIMP
-SameOriginChecker::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
-                                          nsIChannel *aNewChannel,
-                                          uint32_t aFlags,
-                                          nsIAsyncVerifyRedirectCallback *cb)
+SameOriginCheckerImpl::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
+                                              nsIChannel* aNewChannel,
+                                              uint32_t aFlags,
+                                              nsIAsyncVerifyRedirectCallback* cb)
 {
   NS_PRECONDITION(aNewChannel, "Redirecting to null channel?");
 
   nsresult rv = nsContentUtils::CheckSameOrigin(aOldChannel, aNewChannel);
   if (NS_SUCCEEDED(rv)) {
     cb->OnRedirectVerifyCallback(NS_OK);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
-SameOriginChecker::GetInterface(const nsIID & aIID, void **aResult)
+SameOriginCheckerImpl::GetInterface(const nsIID& aIID, void** aResult)
 {
   return QueryInterface(aIID, aResult);
 }
 
 /* static */
 nsresult
 nsContentUtils::GetASCIIOrigin(nsIPrincipal* aPrincipal, nsCString& aOrigin)
 {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1630,17 +1630,17 @@ public:
 
   /**
    * Return whether aStr contains an ASCII uppercase character.
    */
   static bool StringContainsASCIIUpper(const nsAString& aStr);
 
   // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not.
   static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel);
-  static nsIInterfaceRequestor* GetSameOriginChecker();
+  static nsIInterfaceRequestor* SameOriginChecker();
 
   /**
    * Get the Origin of the passed in nsIPrincipal or nsIURI. If the passed in
    * nsIURI or the URI of the passed in nsIPrincipal does not have a host, the
    * origin is set to 'null'.
    *
    * The ASCII versions return a ASCII strings that are puny-code encoded,
    * suitable for, for example, header values. The UTF versions return strings
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -1332,18 +1332,17 @@ nsExternalResourceMap::PendingLoad::Star
   if (NS_FAILED(rv)) return rv;
   if (NS_CP_REJECTED(shouldLoad)) {
     // Disallowed by content policy
     return NS_ERROR_CONTENT_BLOCKED;
   }
 
   nsIDocument* doc = aRequestingNode->OwnerDoc();
 
-  nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
-  NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
+  nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::SameOriginChecker();
 
   nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      aURI,
                      aRequestingNode,
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -4337,20 +4337,21 @@ nsGlobalWindow::GetOwnPropertyNames(JSCo
   nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
   if (nameSpaceManager) {
     GlobalNameEnumeratorClosure closure(aCx, this, aNames);
     nameSpaceManager->EnumerateGlobalNames(EnumerateGlobalName, &closure);
   }
 }
 
 /* static */ bool
-nsGlobalWindow::IsChromeWindow(JSContext* aCx, JSObject* aObj)
+nsGlobalWindow::IsPrivilegedChromeWindow(JSContext* aCx, JSObject* aObj)
 {
   // For now, have to deal with XPConnect objects here.
-  return xpc::WindowOrNull(aObj)->IsChromeWindow();
+  return xpc::WindowOrNull(aObj)->IsChromeWindow() &&
+         nsContentUtils::ObjectPrincipal(aObj) == nsContentUtils::GetSystemPrincipal();
 }
 
 /* static */ bool
 nsGlobalWindow::IsShowModalDialogEnabled(JSContext*, JSObject*)
 {
   static bool sAddedPrefCache = false;
   static bool sIsDisabled;
   static const char sShowModalDialogPref[] = "dom.disable_window_showModalDialog";
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -486,17 +486,17 @@ public:
   // nsIInterfaceRequestor
   NS_DECL_NSIINTERFACEREQUESTOR
 
   // WebIDL interface.
   already_AddRefed<nsIDOMWindow> IndexedGetter(uint32_t aIndex, bool& aFound);
 
   void GetSupportedNames(nsTArray<nsString>& aNames);
 
-  static bool IsChromeWindow(JSContext* /* unused */, JSObject* aObj);
+  static bool IsPrivilegedChromeWindow(JSContext* /* unused */, JSObject* aObj);
 
   static bool IsShowModalDialogEnabled(JSContext* /* unused */ = nullptr,
                                        JSObject* /* unused */ = nullptr);
 
   bool DoResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
                  JS::Handle<jsid> aId,
                  JS::MutableHandle<JSPropertyDescriptor> aDesc);
 
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Preferences.h"
 
 #include "AccessCheck.h"
 #include "jsfriendapi.h"
 #include "nsContentUtils.h"
 #include "nsGlobalWindow.h"
+#include "nsIDocShell.h"
 #include "nsIDOMGlobalPropertyInitializer.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIXPConnect.h"
 #include "nsUTF8Utils.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XrayWrapper.h"
@@ -2376,22 +2377,57 @@ CheckPermissions(JSContext* aCx, JSObjec
     permMgr->TestPermissionFromWindow(window, *aPermissions, &permission);
     if (permission == nsIPermissionManager::ALLOW_ACTION) {
       return true;
     }
   } while (*(++aPermissions));
   return false;
 }
 
+void
+HandlePrerenderingViolation(nsPIDOMWindow* aWindow)
+{
+  // Suspend the window and its workers, and its children too.
+  aWindow->SuspendTimeouts();
+
+  // Suspend event handling on the document
+  nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+  if (doc) {
+    doc->SuppressEventHandling(nsIDocument::eEvents);
+  }
+}
+
 bool
-CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj)
+EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj)
 {
-  //TODO: Check if page is being prerendered.
-  //Returning false for now.
-  return false;
+  JS::Rooted<JSObject*> thisObj(aCx, js::CheckedUnwrap(aObj));
+  if (!thisObj) {
+    // Without a this object, we cannot check the safety.
+    return true;
+  }
+  nsGlobalWindow* window = xpc::WindowGlobalOrNull(thisObj);
+  if (!window) {
+    // Without a window, we cannot check the safety.
+    return true;
+  }
+
+  nsIDocShell* docShell = window->GetDocShell();
+  if (!docShell) {
+    // Without a docshell, we cannot check the safety.
+    return true;
+  }
+
+  if (docShell->GetIsPrerendered()) {
+    HandlePrerenderingViolation(window);
+    // When the bindings layer sees a false return value, it returns false form
+    // the JSNative in order to trigger an uncatchable exception.
+    return false;
+  }
+
+  return true;
 }
 
 bool
 GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
   prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3137,19 +3137,30 @@ AssertReturnTypeMatchesJitinfo(const JSJ
                                JS::Handle<JS::Value> aValue);
 #endif
 
 // Returns true if aObj's global has any of the permissions named in aPermissions
 // set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
 bool
 CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
 
-//Returns true if page is being prerendered.
+// This function is called by the bindings layer for methods/getters/setters
+// that are not safe to be called in prerendering mode.  It checks to make sure
+// that the |this| object is not running in a global that is in prerendering
+// mode.  Otherwise, it aborts execution of timers and event handlers, and
+// returns false which gets converted to an uncatchable exception by the
+// bindings layer.
 bool
-CheckSafetyInPrerendering(JSContext* aCx, JSObject* aObj);
+EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj);
+
+// Handles the violation of a blacklisted action in prerendering mode by
+// aborting the scripts, and preventing timers and event handlers from running
+// in the window in the future.
+void
+HandlePrerenderingViolation(nsPIDOMWindow* aWindow);
 
 bool
 CallerSubsumes(JSObject* aObject);
 
 MOZ_ALWAYS_INLINE bool
 CallerSubsumes(JS::Handle<JS::Value> aValue)
 {
   if (!aValue.isObject()) {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1824,17 +1824,17 @@ addExternalIface('MozFrameRequestCallbac
                  notflattened=True)
 addExternalIface('MozMmsMessage')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
 addExternalIface('MozSmsMessage')
 addExternalIface('MozTreeView', nativeType='nsITreeView',
-                  headerFile='nsITreeView.h')
+                  headerFile='nsITreeView.h', notflattened=True)
 addExternalIface('MozWakeLockListener', headerFile='nsIDOMWakeLockListener.h')
 addExternalIface('MozXULTemplateBuilder', nativeType='nsIXULTemplateBuilder')
 addExternalIface('nsIBrowserDOMWindow', nativeType='nsIBrowserDOMWindow',
                  notflattened=True)
 addExternalIface('nsIControllers', nativeType='nsIControllers')
 addExternalIface('nsIDOMCrypto', nativeType='nsIDOMCrypto',
                  headerFile='Crypto.h')
 addExternalIface('nsIInputStreamCallback', nativeType='nsIInputStreamCallback',
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6501,18 +6501,20 @@ class CGPerSignatureCall(CGThing):
         # inherited interfaces have the UnsafeInPrerendering extended attribute
         # and if so, we add a check to make sure it is safe.
         if (idlNode.getExtendedAttribute("UnsafeInPrerendering") or
             descriptor.interface.getExtendedAttribute("UnsafeInPrerendering") or
             any(i.getExtendedAttribute("UnsafeInPrerendering")
                 for i in descriptor.interface.getInheritedInterfaces())):
                 cgThings.append(CGGeneric(dedent(
                     """
-                    if (mozilla::dom::CheckSafetyInPrerendering(cx, obj)) {
-                        //TODO: Handle call into unsafe API during Prerendering (Bug 730101)
+                    if (!mozilla::dom::EnforceNotInPrerendering(cx, obj)) {
+                        // Return false from the JSNative in order to trigger
+                        // an uncatchable exception.
+                        MOZ_ASSERT(!JS_IsExceptionPending(cx));
                         return false;
                     }
                     """)))
         lenientFloatCode = None
         if idlNode.getExtendedAttribute('LenientFloat') is not None:
             if setter:
                 lenientFloatCode = "return true;\n"
             elif idlNode.isMethod():
--- a/dom/bindings/test/chrome.ini
+++ b/dom/bindings/test/chrome.ini
@@ -1,8 +1,13 @@
 [DEFAULT]
 
 [test_bug707564-chrome.html]
 [test_bug775543.html]
 [test_document_location_set_via_xray.html]
 [test_dom_xrays.html]
 [test_proxies_via_xray.html]
 [test_document_location_via_xray_cached.html]
+[test_blacklisted_prerendering_function.xul]
+support-files =
+  file_focuser.html
+  file_fullScreenPropertyAccessor.html
+skip-if = e10s # prerendering doesn't work in e10s yet
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/file_focuser.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<div id="stage"></div>
+<script>
+  function stage(str) {
+    var s = document.getElementById("stage");
+    s.textContent = str;
+  }
+  stage("before");
+  setTimeout(function() {
+    stage("in timeout");
+  });
+  setInterval(function() {
+    stage("in interval");
+  });
+  addEventListener("keydown", function() {
+    stage("keydown");
+  }, false);
+  try {
+    focus();
+    stage("after");
+  } catch(e) {
+    stage("exception raised");
+  }
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/file_fullScreenPropertyAccessor.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<div id="stage"></div>
+<script>
+  function stage(str) {
+    var s = document.getElementById("stage");
+    s.textContent = str;
+  }
+  stage("before");
+  setTimeout(function() {
+    stage("in timeout");
+  });
+  setInterval(function() {
+    stage("in interval");
+  });
+  addEventListener("keydown", function() {
+    stage("keydown");
+  }, false);
+  try {
+    window.fullScreen;
+    stage("after");
+  } catch(e) {
+    stage("exception raised");
+  }
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/test_blacklisted_prerendering_function.xul
@@ -0,0 +1,124 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        xmlns:html="http://www.w3.org/1999/xhtml"
+        onload="runTest();">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+<script class="testbody" type="application/javascript">
+<![CDATA[
+
+  SimpleTest.waitForExplicitFinish();
+
+  function Listener(aBrowser, aPrerendered, aCallback) {
+    this.init(aBrowser, aPrerendered, aCallback);
+  }
+
+  Listener.prototype = {
+    init: function(aBrowser, aPrerendered, aCallback) {
+      this.mBrowser = aBrowser;
+      this.mPrerendered = aPrerendered;
+      this.mCallback = aCallback;
+    },
+    QueryInterface: function(aIID) {
+      if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
+          aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
+          aIID.equals(Components.interfaces.nsISupports))
+        return this;
+      throw Components.results.NS_NOINTERFACE;
+    },
+    onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {
+      if ((aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_STOP) &&
+          (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT)) {
+        var doc = this.mBrowser.contentDocument;
+        var stage = doc.getElementById("stage");
+        if (this.mPrerendered) {
+          is(stage.textContent, "before", "The blacklisted call should properly be intercepted in prerendering mode");
+        } else {
+          // In normal mode, we may or may not have run the timeout and/or the interval.
+          switch (stage.textContent) {
+          case "after":
+          case "in timeout":
+          case "in interval":
+            ok(true, "The blacklisted call should work fine in normal mode");
+            break;
+          default:
+            ok(false, "The blacklisted call should work fine in normal mode");
+            break;
+          }
+        }
+        progress.removeProgressListener(progressListener);
+
+        // Set three timeouts to see if the interval triggered
+        var self = this;
+        function checkInterval() {
+          var expected = self.mPrerendered ? "before" : "in interval";
+          var desc = self.mPrerendered ? "No timer should be running" : "Timers should run as normal";
+          is(stage.textContent, expected, desc);
+          // Now, dispatch a key event to the window and see if the keydown handler runs
+          synthesizeKey("a", {}, self.mBrowser.contentWindow);
+          expected = self.mPrerendered ? "before" : "keydown";
+          desc = self.mPrerendered ? "No event handler should be running" : "Event handlers should run as normal";
+          is(stage.textContent, expected, desc);
+          self.mCallback();
+        }
+        setTimeout(function() {
+          setTimeout(function() {
+            setTimeout(function() {
+              checkInterval();
+            }, 0);
+          }, 0);
+        }, 0);
+      }
+    },
+    onProgressChange : function(aWebProgress, aRequest,
+                                aCurSelfProgress, aMaxSelfProgress,
+                                aCurTotalProgress, aMaxTotalProgress) {},
+    onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) {},
+    onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {},
+    onSecurityChange : function(aWebProgress, aRequest, aState) {},
+    mBrowser: null,
+    mPrerendered: false,
+    mCallback: null
+  };
+
+  var progress, progressListener;
+
+  function runTest() {
+    testStep(false, "file_focuser.html", function() {
+      testStep(true, "file_focuser.html", function() {
+        testStep(false, "file_fullScreenPropertyAccessor.html", function() {
+          testStep(true, "file_fullScreenPropertyAccessor.html", function() {
+            SimpleTest.finish();
+          });
+        });
+      });
+    });
+  }
+
+  function testStep(aPrerendered, aFileName, aCallback) {
+    var browser = document.getElementById(aPrerendered ? "prerendered" : "normal");;
+    progressListener = new Listener(browser, aPrerendered, aCallback);
+    var docShell = browser.docShell;
+    progress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+                       .getInterface(Components.interfaces.nsIWebProgress);
+    progress.addProgressListener(progressListener,
+                                 Components.interfaces.nsIWebProgress.NOTIFY_ALL);
+    browser.loadURI("chrome://mochitests/content/chrome/dom/bindings/test/" + aFileName);
+  }
+
+]]>
+</script>
+
+<body  id="html_body" xmlns="http://www.w3.org/1999/xhtml">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1069719">Mozilla Bug 1069719</a>
+<p id="display"></p>
+
+<pre id="test">
+</pre>
+</body>
+<browser prerendered="true" id="prerendered"/>
+<browser id="normal"/>
+</window>
--- a/dom/media/gmp/GMPLoader.cpp
+++ b/dom/media/gmp/GMPLoader.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Attributes.h"
 #include "gmp-entrypoints.h"
 #include "prlink.h"
 
 #include <string>
 
 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 #include "mozilla/sandboxTarget.h"
+#include "mozilla/Scoped.h"
 #include "windows.h"
 #include <intrin.h>
 #include <assert.h>
 #endif
 
 #if defined(HASH_NODE_ID_WITH_DEVICE_ID)
 // In order to provide EME plugins with a "device binding" capability,
 // in the parent we generate and store some random bytes as salt for every
@@ -28,16 +29,41 @@
 // device specific data and munges that with the salt to create the
 // "node id" that we expose to EME plugins. It then overwrites the device
 // specific data, and activates the sandbox.
 #include "rlz/lib/machine_id.h"
 #include "rlz/lib/string_utils.h"
 #include "sha256.h"
 #endif
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+namespace {
+
+// Scoped type used by Load
+struct ScopedActCtxHandleTraits
+{
+  typedef HANDLE type;
+
+  static type empty()
+  {
+    return INVALID_HANDLE_VALUE;
+  }
+
+  static void release(type aActCtxHandle)
+  {
+    if (aActCtxHandle != INVALID_HANDLE_VALUE) {
+      ReleaseActCtx(aActCtxHandle);
+    }
+  }
+};
+typedef mozilla::Scoped<ScopedActCtxHandleTraits> ScopedActCtxHandle;
+
+} // anonymous namespace
+#endif
+
 namespace mozilla {
 namespace gmp {
 
 class GMPLoaderImpl : public GMPLoader {
 public:
   explicit GMPLoaderImpl(SandboxStarter* aStarter)
     : mSandboxStarter(aStarter)
   {}
@@ -163,16 +189,40 @@ GMPLoaderImpl::Load(const char* aLibPath
       *p = 0;
     }
   } else
 #endif
   {
     nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen);
   }
 
+#if defined(XP_WIN) && defined(MOZ_SANDBOX)
+  // If the GMP DLL is a side-by-side assembly with static imports then the DLL
+  // loader will attempt to create an activation context which will fail because
+  // of the sandbox. If we create an activation context before we start the
+  // sandbox then this one will get picked up by the DLL loader.
+  int pathLen = MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, nullptr, 0);
+  if (pathLen == 0) {
+    return false;
+  }
+
+  wchar_t* widePath = new wchar_t[pathLen];
+  if (MultiByteToWideChar(CP_ACP, 0, aLibPath, -1, widePath, pathLen) == 0) {
+    delete[] widePath;
+    return false;
+  }
+
+  ACTCTX actCtx = { sizeof(actCtx) };
+  actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
+  actCtx.lpSource = widePath;
+  actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
+  ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx));
+  delete[] widePath;
+#endif
+
   // Start the sandbox now that we've generated the device bound node id.
   // This must happen after the node id is bound to the device id, as
   // generating the device id requires privileges.
   if (mSandboxStarter) {
     mSandboxStarter->Start(aLibPath);
   }
 
   // Load the GMP.
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -14,16 +14,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/MediaSourceBinding.h"
 #include "mozilla/dom/TimeRanges.h"
 #include "nsError.h"
 #include "nsIEventTarget.h"
 #include "nsIRunnable.h"
 #include "nsThreadUtils.h"
 #include "prlog.h"
+#include <time.h>
 
 struct JSContext;
 class JSObject;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
@@ -31,24 +32,47 @@ extern PRLogModuleInfo* GetMediaSourceAP
 #define MSE_DEBUGV(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG+1, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
 #define MSE_DEBUG(...)
 #define MSE_DEBUGV(...)
 #define MSE_API(...)
 #endif
 
-// RangeRemoval must be synchronous if appendBuffer is also synchronous.
-// While waiting for bug 1118589 to land, ensure RangeRemoval is synchronous
-#define APPENDBUFFER_IS_SYNCHRONOUS
-
 namespace mozilla {
 
 namespace dom {
 
+class AppendDataRunnable : public nsRunnable {
+public:
+  AppendDataRunnable(SourceBuffer* aSourceBuffer,
+                     const uint8_t* aData,
+                     uint32_t aLength,
+                     double aTimestampOffset)
+  : mSourceBuffer(aSourceBuffer)
+  , mTimestampOffset(aTimestampOffset)
+  {
+    mData.AppendElements(aData, aLength);
+  }
+
+  NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
+
+    mSourceBuffer->AppendData(mData.Elements(),
+                              mData.Length(),
+                              mTimestampOffset);
+
+    return NS_OK;
+  }
+
+private:
+  nsRefPtr<SourceBuffer> mSourceBuffer;
+  nsTArray<uint8_t> mData;
+  double mTimestampOffset;
+};
+
 class RangeRemovalRunnable : public nsRunnable {
 public:
   RangeRemovalRunnable(SourceBuffer* aSourceBuffer,
                      double aStart,
                      double aEnd)
   : mSourceBuffer(aSourceBuffer)
   , mStart(aStart)
   , mEnd(aEnd)
@@ -235,46 +259,34 @@ SourceBuffer::Remove(double aStart, doub
   RangeRemoval(aStart, aEnd);
 }
 
 void
 SourceBuffer::RangeRemoval(double aStart, double aEnd)
 {
   StartUpdating();
 
-#if defined(APPENDBUFFER_IS_SYNCHRONOUS)
-  DoRangeRemoval(aStart, aEnd);
-
-  // Run the final step of the buffer append algorithm asynchronously to
-  // ensure the SourceBuffer's updating flag transition behaves as required
-  // by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-#else
   nsRefPtr<nsIRunnable> task = new RangeRemovalRunnable(this, aStart, aEnd);
   NS_DispatchToMainThread(task);
-#endif
 }
 
 void
 SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
 {
   if (!mUpdating) {
     // abort was called in between.
     return;
   }
   if (mTrackBuffer && !IsInfinite(aStart)) {
     int64_t start = aStart * USECS_PER_S;
     int64_t end = IsInfinite(aEnd) ? INT64_MAX : (int64_t)(aEnd * USECS_PER_S);
     mTrackBuffer->RangeRemoval(start, end);
   }
 
-#if !defined(APPENDBUFFER_IS_SYNCHRONOUS)
   StopUpdating();
-#endif
 }
 
 void
 SourceBuffer::Detach()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MSE_DEBUG("SourceBuffer(%p)::Detach", this);
   Abort();
@@ -400,36 +412,51 @@ SourceBuffer::AppendData(const uint8_t* 
   MSE_DEBUG("SourceBuffer(%p)::AppendData(aLength=%u)", this, aLength);
   if (!PrepareAppend(aRv)) {
     return;
   }
   StartUpdating();
 
   MOZ_ASSERT(mAppendMode == SourceBufferAppendMode::Segments,
              "We don't handle timestampOffset for sequence mode yet");
+  nsRefPtr<nsIRunnable> task =
+    new AppendDataRunnable(this, aData, aLength, mTimestampOffset);
+  NS_DispatchToMainThread(task);
+}
+
+void
+SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, double aTimestampOffset)
+{
+  if (!mUpdating) {
+    // The buffer append algorithm has been interrupted by abort().
+    //
+    // If the sequence appendBuffer(), abort(), appendBuffer() occurs before
+    // the first StopUpdating() runnable runs, then a second StopUpdating()
+    // runnable will be scheduled, but still only one (the first) will queue
+    // events.
+    return;
+  }
+
+  MOZ_ASSERT(mMediaSource);
+
   if (aLength) {
-    if (!mTrackBuffer->AppendData(aData, aLength, mTimestampOffset * USECS_PER_S)) {
-      nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethodWithArg<bool>(this, &SourceBuffer::AppendError, true);
-      NS_DispatchToMainThread(event);
+    if (!mTrackBuffer->AppendData(aData, aLength, aTimestampOffset * USECS_PER_S)) {
+      AppendError(true);
       return;
     }
 
     if (mTrackBuffer->HasInitSegment()) {
       mMediaSource->QueueInitializationEvent();
     }
 
     CheckEndTime();
   }
 
-  // Run the final step of the buffer append algorithm asynchronously to
-  // ensure the SourceBuffer's updating flag transition behaves as required
-  // by the spec.
-  nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &SourceBuffer::StopUpdating);
-  NS_DispatchToMainThread(event);
-}
+  StopUpdating();
+ }
 
 void
 SourceBuffer::AppendError(bool aDecoderError)
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!mUpdating) {
     // The buffer append algorithm has been interrupted by abort().
     return;
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -117,31 +117,34 @@ public:
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~SourceBuffer();
 
   friend class AsyncEventRunner<SourceBuffer>;
+  friend class AppendDataRunnable;
   void DispatchSimpleEvent(const char* aName);
   void QueueAsyncSimpleEvent(const char* aName);
 
   // Update mUpdating and fire the appropriate events.
   void StartUpdating();
   void StopUpdating();
   void AbortUpdating();
 
   // If the media segment contains data beyond the current duration,
   // then run the duration change algorithm with new duration set to the
   // maximum of the current duration and the group end timestamp.
   void CheckEndTime();
 
   // Shared implementation of AppendBuffer overloads.
   void AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv);
+  void AppendData(const uint8_t* aData, uint32_t aLength,
+                  double aTimestampOffset);
 
   // Implement the "Append Error Algorithm".
   // Will call endOfStream() with "decode" error if aDecodeError is true.
   // 3.5.3 Append Error Algorithm
   // http://w3c.github.io/media-source/#sourcebuffer-append-error
   void AppendError(bool aDecoderError);
 
   // Implements the "Prepare Append Algorithm".  Returns true if the append
--- a/dom/media/mediasource/SourceBufferDecoder.cpp
+++ b/dom/media/mediasource/SourceBufferDecoder.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SourceBufferDecoder.h"
 #include "prlog.h"
 #include "AbstractMediaDecoder.h"
 #include "MediaDecoderReader.h"
+#include "mozilla/dom/TimeRanges.h"
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* GetMediaSourceLog();
 extern PRLogModuleInfo* GetMediaSourceAPILog();
 
 #define MSE_DEBUG(...) PR_LOG(GetMediaSourceLog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #define MSE_API(...) PR_LOG(GetMediaSourceAPILog(), PR_LOG_DEBUG, (__VA_ARGS__))
 #else
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -400,77 +400,77 @@ partial interface Window {
 partial interface Window {
   [Replaceable, Throws]
   readonly attribute (External or WindowProxy) sidebar;
 };
 #endif
 
 [Func="IsChromeOrXBL"]
 interface ChromeWindow {
-  [Func="nsGlobalWindow::IsChromeWindow"]
+  [Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   const unsigned short STATE_MAXIMIZED = 1;
-  [Func="nsGlobalWindow::IsChromeWindow"]
+  [Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   const unsigned short STATE_MINIMIZED = 2;
-  [Func="nsGlobalWindow::IsChromeWindow"]
+  [Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   const unsigned short STATE_NORMAL = 3;
-  [Func="nsGlobalWindow::IsChromeWindow"]
+  [Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   const unsigned short STATE_FULLSCREEN = 4;
 
-  [Func="nsGlobalWindow::IsChromeWindow"]
+  [Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   readonly attribute unsigned short windowState;
 
   /**
    * browserDOMWindow provides access to yet another layer of
    * utility functions implemented by chrome script. It will be null
    * for DOMWindows not corresponding to browsers.
    */
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
            attribute nsIBrowserDOMWindow? browserDOMWindow;
 
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   void                      getAttention();
 
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   void                      getAttentionWithCycleCount(long aCycleCount);
 
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   void                      setCursor(DOMString cursor);
 
-  [Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
   void                      maximize();
-  [Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
   void                      minimize();
-  [Throws, Func="nsGlobalWindow::IsChromeWindow", UnsafeInPrerendering]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow", UnsafeInPrerendering]
   void                      restore();
 
   /**
    * Notify a default button is loaded on a dialog or a wizard.
    * defaultButton is the default button.
    */
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   void notifyDefaultButtonLoaded(Element defaultButton);
 
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   readonly attribute nsIMessageBroadcaster messageManager;
 
   /**
    * Returns the message manager identified by the given group name that
    * manages all frame loaders belonging to that group.
    */
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   nsIMessageBroadcaster getGroupMessageManager(DOMString aGroup);
 
   /**
    * On some operating systems, we must allow the window manager to
    * handle window dragging. This function tells the window manager to
    * start dragging the window. This function will fail unless called
    * while the left mouse button is held down, callers must check this.
    *
    * The optional panel argument should be set when moving a panel.
    *
    * Throws NS_ERROR_NOT_IMPLEMENTED if the OS doesn't support this.
    */
-  [Throws, Func="nsGlobalWindow::IsChromeWindow"]
+  [Throws, Func="nsGlobalWindow::IsPrivilegedChromeWindow"]
   void beginWindowMove(Event mouseDownEvent, optional Element? panel = null);
 };
 
 Window implements ChromeWindow;
 Window implements GlobalFetch;
--- a/dom/workers/ServiceWorkerRegistration.h
+++ b/dom/workers/ServiceWorkerRegistration.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ServiceWorkerRegistration_h
 #define mozilla_dom_ServiceWorkerRegistration_h
 
 #include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/ServiceWorkerBinding.h"
 #include "mozilla/dom/ServiceWorkerCommon.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class Promise;
--- a/dom/xbl/nsXBLService.cpp
+++ b/dom/xbl/nsXBLService.cpp
@@ -1095,18 +1095,17 @@ nsXBLService::FetchBindingDocument(nsICo
                        nsContentUtils::GetSystemPrincipal(),
                        nsILoadInfo::SEC_NORMAL,
                        nsIContentPolicy::TYPE_OTHER,
                        loadGroup);
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
-  NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
+  nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::SameOriginChecker();
 
   channel->SetNotificationCallbacks(sameOriginChecker);
 
   if (!aForceSyncLoad) {
     // We can be asynchronous
     nsXBLStreamListener* xblListener =
       new nsXBLStreamListener(aBoundDocument, xblSink, doc);
     NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
--- a/dom/xml/XMLDocument.cpp
+++ b/dom/xml/XMLDocument.cpp
@@ -429,21 +429,17 @@ XMLDocument::Load(const nsAString& aUrl,
     loadGroup = callingDoc->GetDocumentLoadGroup();
   }
 
   ResetToURI(uri, loadGroup, principal);
 
   mListenerManager = elm;
 
   // Create a channel
-  nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
-  if (!req) {
-    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return false;
-  }
+  nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::SameOriginChecker();
 
   nsCOMPtr<nsIChannel> channel;
   // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active,
   // which in turn keeps STOP button from becoming active  
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      callingDoc ? callingDoc.get() :
                                   static_cast<nsIDocument*>(this),
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -103,17 +103,17 @@ public:
    * Returns true if there's any progress to report.
    */
   bool HasProgress() const
   {
     return mProgress != NoProgress || !mInvalidRect.IsEmpty();
   }
 
   // We're not COM-y, so we don't get refcounts by default
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder)
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Decoder, MOZ_OVERRIDE)
 
   // Implement IResumable.
   virtual void Resume() MOZ_OVERRIDE;
 
   /*
    * State.
    */
 
--- a/js/src/asmjs/AsmJSModule.cpp
+++ b/js/src/asmjs/AsmJSModule.cpp
@@ -448,55 +448,55 @@ AsmJSModule::setAutoFlushICacheRange()
 {
     MOZ_ASSERT(isFinished());
     AutoFlushICache::setRange(uintptr_t(code_), pod.codeBytes_);
 }
 
 static void
 AsmJSReportOverRecursed()
 {
-    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
     js_ReportOverRecursed(cx);
 }
 
 static void
 OnDetached()
 {
     // See hasDetachedHeap comment in LinkAsmJS.
-    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
     JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
 }
 
 static bool
 AsmJSHandleExecutionInterrupt()
 {
-    AsmJSActivation *act = PerThreadData::innermostAsmJSActivation();
+    AsmJSActivation *act = JSRuntime::innermostAsmJSActivation();
     act->module().setInterrupted(true);
     bool ret = CheckForInterrupt(act->cx());
     act->module().setInterrupted(false);
     return ret;
 }
 
 static int32_t
 CoerceInPlace_ToInt32(MutableHandleValue val)
 {
-    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
 
     int32_t i32;
     if (!ToInt32(cx, val, &i32))
         return false;
     val.set(Int32Value(i32));
 
     return true;
 }
 
 static int32_t
 CoerceInPlace_ToNumber(MutableHandleValue val)
 {
-    JSContext *cx = PerThreadData::innermostAsmJSActivation()->cx();
+    JSContext *cx = JSRuntime::innermostAsmJSActivation()->cx();
 
     double dbl;
     if (!ToNumber(cx, val, &dbl))
         return false;
     val.set(DoubleValue(dbl));
 
     return true;
 }
@@ -565,29 +565,29 @@ InvokeFromAsmJS(AsmJSActivation *activat
     return TryEnablingJit(cx, module, fun, exitIndex, argc, argv);
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
 InvokeFromAsmJS_Ignore(int32_t exitIndex, int32_t argc, Value *argv)
 {
-    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
     JSContext *cx = activation->cx();
 
     RootedValue rval(cx);
     return InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval);
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
 InvokeFromAsmJS_ToInt32(int32_t exitIndex, int32_t argc, Value *argv)
 {
-    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
     JSContext *cx = activation->cx();
 
     RootedValue rval(cx);
     if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval))
         return false;
 
     int32_t i32;
     if (!ToInt32(cx, rval, &i32))
@@ -597,17 +597,17 @@ InvokeFromAsmJS_ToInt32(int32_t exitInde
     return true;
 }
 
 // Use an int32_t return type instead of bool since bool does not have a
 // specified width and the caller is assuming a word-sized return.
 static int32_t
 InvokeFromAsmJS_ToNumber(int32_t exitIndex, int32_t argc, Value *argv)
 {
-    AsmJSActivation *activation = PerThreadData::innermostAsmJSActivation();
+    AsmJSActivation *activation = JSRuntime::innermostAsmJSActivation();
     JSContext *cx = activation->cx();
 
     RootedValue rval(cx);
     if (!InvokeFromAsmJS(activation, exitIndex, argc, argv, &rval))
         return false;
 
     double dbl;
     if (!ToNumber(cx, rval, &dbl))
--- a/js/src/asmjs/AsmJSSignalHandlers.cpp
+++ b/js/src/asmjs/AsmJSSignalHandlers.cpp
@@ -443,17 +443,17 @@ HandleFault(PEXCEPTION_POINTERS exceptio
         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();
+    AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
 # if defined(JS_CODEGEN_X64)
     const AsmJSModule &module = activation->module();
 
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
@@ -642,17 +642,17 @@ HandleMachException(JSRuntime *rt, const
         return false;
 
     uint8_t **ppc = ContextToPC(state);
     uint8_t *pc = *ppc;
 
     if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2)
         return false;
 
-    AsmJSActivation *activation = rt->mainThread.asmJSActivationStack();
+    AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
 # if defined(JS_CPU_X64)
@@ -856,17 +856,17 @@ HandleFault(int signum, siginfo_t *info,
     uint8_t *pc = *ppc;
 
     // 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();
+    AsmJSActivation *activation = rt->asmJSActivationStack();
     if (!activation)
         return false;
 
     const AsmJSModule &module = activation->module();
     if (!module.containsFunctionPC(pc))
         return false;
 
 # if defined(JS_CODEGEN_X64)
@@ -942,22 +942,22 @@ RedirectIonBackedgesToInterruptCheck(JSR
     }
 }
 
 static void
 RedirectJitCodeToInterruptCheck(JSRuntime *rt, CONTEXT *context)
 {
     RedirectIonBackedgesToInterruptCheck(rt);
 
-    if (AsmJSActivation *activation = rt->mainThread.asmJSActivationStack()) {
+    if (AsmJSActivation *activation = rt->asmJSActivationStack()) {
         const AsmJSModule &module = activation->module();
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-        if (module.containsFunctionPC((void*)rt->mainThread.simulator()->get_pc()))
-            rt->mainThread.simulator()->set_resume_pc(int32_t(module.interruptExit()));
+        if (module.containsFunctionPC((void*)rt->simulator()->get_pc()))
+            rt->simulator()->set_resume_pc(int32_t(module.interruptExit()));
 #endif
 
         uint8_t **ppc = ContextToPC(context);
         uint8_t *pc = *ppc;
         if (module.containsFunctionPC(pc)) {
             activation->setResumePC(pc);
             *ppc = module.interruptExit();
         }
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -8499,63 +8499,59 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         MOZ_ASSERT(callee == AsmJSIonExitRegCallee);
         Register reg0 = AsmJSIonExitRegE0;
         Register reg1 = AsmJSIonExitRegE1;
         Register reg2 = AsmJSIonExitRegE2;
         Register reg3 = AsmJSIonExitRegE3;
 
         // The following is inlined:
         //   JSContext *cx = activation->cx();
-        //   Activation *act = cx->mainThread().activation();
+        //   Activation *act = cx->runtime()->activation();
         //   act.active_ = true;
-        //   act.prevJitTop_ = cx->mainThread().jitTop;
-        //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
-        //   cx->mainThread().jitJSContext = cx;
-        //   act.prevJitActivation_ = cx->mainThread().jitActivation;
-        //   cx->mainThread().jitActivation = act;
-        //   act.prevProfilingActivation_ = cx->mainThread().profilingActivation;
-        //   cx->mainThread().profilingActivation_ = act;
+        //   act.prevJitTop_ = cx->runtime()->jitTop;
+        //   act.prevJitJSContext_ = cx->runtime()->jitJSContext;
+        //   cx->runtime()->jitJSContext = cx;
+        //   act.prevJitActivation_ = cx->runtime()->jitActivation;
+        //   cx->runtime()->jitActivation = act;
+        //   act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
+        //   cx->runtime()->profilingActivation_ = act;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
-                                    PerThreadData::offsetOfActivation();
-        size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
-                                      offsetof(PerThreadData, jitJSContext);
-        size_t offsetOfJitActivation = offsetof(JSRuntime, mainThread) +
-                                       offsetof(PerThreadData, jitActivation);
-        size_t offsetOfProfilingActivation = offsetof(JSRuntime, mainThread) +
-                                             PerThreadData::offsetOfProfilingActivation();
+        size_t offsetOfActivation = JSRuntime::offsetOfActivation();
+        size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
+        size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
+        size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
+        size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
         masm.loadAsmJSActivation(reg0);
         masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3);
         masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0);
         masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
 
         //   act.active_ = true;
         masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8()));
 
-        //   act.prevJitTop_ = cx->mainThread().jitTop;
+        //   act.prevJitTop_ = cx->runtime()->jitTop;
         masm.loadPtr(Address(reg0, offsetOfJitTop), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop()));
 
-        //   act.prevJitJSContext_ = cx->mainThread().jitJSContext;
+        //   act.prevJitJSContext_ = cx->runtime()->jitJSContext;
         masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext()));
-        //   cx->mainThread().jitJSContext = cx;
+        //   cx->runtime()->jitJSContext = cx;
         masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext));
 
-        //   act.prevJitActivation_ = cx->mainThread().jitActivation;
+        //   act.prevJitActivation_ = cx->runtime()->jitActivation;
         masm.loadPtr(Address(reg0, offsetOfJitActivation), reg2);
         masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitActivation()));
-        //   cx->mainThread().jitActivation = act;
+        //   cx->runtime()->jitActivation = act;
         masm.storePtr(reg1, Address(reg0, offsetOfJitActivation));
 
-        //   act.prevProfilingActivation_ = cx->mainThread().profilingActivation;
+        //   act.prevProfilingActivation_ = cx->runtime()->profilingActivation;
         masm.loadPtr(Address(reg0, offsetOfProfilingActivation), reg2);
         masm.storePtr(reg2, Address(reg1, Activation::offsetOfPrevProfiling()));
-        //   cx->mainThread().profilingActivation_ = act;
+        //   cx->runtime()->profilingActivation_ = act;
         masm.storePtr(reg1, Address(reg0, offsetOfProfilingActivation));
     }
 
     // 2. Call
     AssertStackAlignment(masm, AsmJSStackAlignment);
     masm.callJitFromAsmJS(callee);
     AssertStackAlignment(masm, AsmJSStackAlignment);
 
@@ -8566,51 +8562,47 @@ GenerateFFIIonExit(ModuleCompiler &m, co
         // JSReturnReg_Type, so there are five live registers.
         MOZ_ASSERT(JSReturnReg_Data == AsmJSIonExitRegReturnData);
         MOZ_ASSERT(JSReturnReg_Type == AsmJSIonExitRegReturnType);
         Register reg0 = AsmJSIonExitRegD0;
         Register reg1 = AsmJSIonExitRegD1;
         Register reg2 = AsmJSIonExitRegD2;
 
         // The following is inlined:
-        //   rt->mainThread.profilingActivation = prevProfilingActivation_;
-        //   rt->mainThread.activation()->active_ = false;
-        //   rt->mainThread.jitTop = prevJitTop_;
-        //   rt->mainThread.jitJSContext = prevJitJSContext_;
-        //   rt->mainThread.jitActivation = prevJitActivation_;
+        //   rt->profilingActivation = prevProfilingActivation_;
+        //   rt->activation()->active_ = false;
+        //   rt->jitTop = prevJitTop_;
+        //   rt->jitJSContext = prevJitJSContext_;
+        //   rt->jitActivation = prevJitActivation_;
         // On the ARM store8() uses the secondScratchReg (lr) as a temp.
-        size_t offsetOfActivation = offsetof(JSRuntime, mainThread) +
-                                    PerThreadData::offsetOfActivation();
-        size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop);
-        size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) +
-                                      offsetof(PerThreadData, jitJSContext);
-        size_t offsetOfJitActivation = offsetof(JSRuntime, mainThread) +
-                                       offsetof(PerThreadData, jitActivation);
-        size_t offsetOfProfilingActivation = offsetof(JSRuntime, mainThread) +
-                                             PerThreadData::offsetOfProfilingActivation();
+        size_t offsetOfActivation = JSRuntime::offsetOfActivation();
+        size_t offsetOfJitTop = offsetof(JSRuntime, jitTop);
+        size_t offsetOfJitJSContext = offsetof(JSRuntime, jitJSContext);
+        size_t offsetOfJitActivation = offsetof(JSRuntime, jitActivation);
+        size_t offsetOfProfilingActivation = JSRuntime::offsetOfProfilingActivation();
 
         masm.movePtr(AsmJSImmPtr(AsmJSImm_Runtime), reg0);
         masm.loadPtr(Address(reg0, offsetOfActivation), reg1);
 
-        //   rt->mainThread.jitTop = prevJitTop_;
+        //   rt->jitTop = prevJitTop_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitTop()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitTop));
 
-        //   rt->mainThread.profilingActivation = rt->mainThread.activation()->prevProfiling_;
+        //   rt->profilingActivation = rt->activation()->prevProfiling_;
         masm.loadPtr(Address(reg1, Activation::offsetOfPrevProfiling()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfProfilingActivation));
 
-        //   rt->mainThread.activation()->active_ = false;
+        //   rt->activation()->active_ = false;
         masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8()));
 
-        //   rt->mainThread.jitJSContext = prevJitJSContext_;
+        //   rt->jitJSContext = prevJitJSContext_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext));
 
-        //   rt->mainThread.jitActivation = prevJitActivation_;
+        //   rt->jitActivation = prevJitActivation_;
         masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitActivation()), reg2);
         masm.storePtr(reg2, Address(reg0, offsetOfJitActivation));
     }
 
     MOZ_ASSERT(masm.framePushed() == framePushed);
 
     // Reload the global register since Ion code can clobber any register.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -1348,21 +1348,21 @@ js::testingFunc_assertFloat32(JSContext 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // NOP when not in IonMonkey
     args.rval().setUndefined();
     return true;
 }
 
 static bool
-TestingFunc_assertValidJitStack(JSContext *cx, unsigned argc, jsval *vp)
+TestingFunc_assertJitStackInvariants(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    jit::AssertValidJitStack(cx);
+    jit::AssertJitStackInvariants(cx);
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 SetJitCompilerOption(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -2494,18 +2494,18 @@ gc::ZealModeHelpText),
     JS_FN_HELP("getObjectMetadata", GetObjectMetadata, 1, 0,
 "getObjectMetadata(obj)",
 "  Get the metadata for an object."),
 
     JS_FN_HELP("bailout", testingFunc_bailout, 0, 0,
 "bailout()",
 "  Force a bailout out of ionmonkey (if running in ionmonkey)."),
 
-    JS_FN_HELP("assertValidJitStack", TestingFunc_assertValidJitStack, 0, 0,
-"assertValidJitStack()",
+    JS_FN_HELP("assertJitStackInvariants", TestingFunc_assertJitStackInvariants, 0, 0,
+"assertJitStackInvariants()",
 "  Iterates the Jit stack and check that stack invariants hold."),
 
     JS_FN_HELP("setJitCompilerOption", SetJitCompilerOption, 2, 0,
 "setCompilerOption(<option>, <number>)",
 "  Set a compiler option indexed in JSCompileOption enum to a number.\n"),
 
     JS_FN_HELP("setIonCheckGraphCoherency", SetIonCheckGraphCoherency, 1, 0,
 "setIonCheckGraphCoherency(bool)",
--- a/js/src/devtools/rootAnalysis/README.txt
+++ b/js/src/devtools/rootAnalysis/README.txt
@@ -1,39 +1,49 @@
+# Spidermonkey JSAPI rooting analysis
+
 This directory contains scripts and a makefile for running Brian Hackett's
 static GC rooting analysis on a JS source directory.
 
-To use it:
+To use it on SpiderMonkey:
+
+1.  Be on Fedora/CentOS/RedHat Linux x86_64.
 
-1. Download and compile sixgill. Make sure the gcc plugin is enabled. (The
-   configure output will tell you.)
-
-  - [sfink] I needed a couple of patches to get it work on Fedora 16/17/18.
-    Ask me if you need them.
+    (Specifically, the prebuilt GCC **won't work on Ubuntu**
+    without the `CFLAGS` and `CXXFLAGS` settings from
+    http://trac.wildfiregames.com/wiki/StaticRootingAnalysis .)
 
-2. Compile an optimized JS shell that includes the patch at
-   <http://people.mozilla.org/~sfink/data/bug-835552-cwd-snarf>. This does not
-   need to be in the same source tree as you are running these scripts from.
-   Remember the full path to the resulting JS binary; we'll call it $JS_SHELL
-   below.
+2.  Have the Gecko build prerequisites installed.
+
+3.  In this directory, run these commands.
 
-3. |make clean| in the objdir of the JS source tree that you're going to be
-   analyzing. (These analysis scripts will default to the tree they are within,
-   but you can point them at another tree.)
+        mkdir builddir
+        cd builddir
+        ../run-analysis.sh
 
-4. in $objdir/js/src/devtools/analysis, |make JS=$JS_SHELL
-   SIXGILL=.../path/to/sixgill...|. You may need one or more of the following
-   additional settings in addition to the |JS| already given:
+`run-analysis.sh` is kind of like `configure` and `make` combined:
+the build directory can be wherever you want
+and you can name it whatever you want.
+(You could just run it right here in the source tree, and it would work,
+but don't do that -- it spits out files all over the place and
+then you'd have to clean up your source tree later.)
 
-   - JSOBJDIR: if you are analyzing a different source tree, set this to the
-     objdir of the tree you want to analyze.
+Output goes to `hazards.txt` in the builddir.
+
+To use this analysis on any other codebase,
+make a copy of `run-analysis.sh` and adapt it for your code.
+
 
-   - ANALYSIS_SCRIPT_DIR: by default, the *.js files within the directory
-     containing this README will be used, but you can point to a different
-     directory full. At the time of this writing, there are some changes not in
-     bhackett's git repo that are necessary, and you'll also need the
-     gen-hazards.sh shell script.
+## Overview of what is going on here
+
+So what does `run-analysis.sh` actually do?
+
+1.  **It insecurely downloads software over HTTP.** Yeah.
+    See `run-analysis.sh` for details.
 
-   - JOBS: set this to the number of parallel jobs you'd like to run the final
-     analysis pass with. This defaults to 6, somewhat randomly, which gave me a
-     large speedup even on a machine with only 2 cores.
+2.  It runs `run_complete`, a Perl script, which builds the target
+    codebase with a custom hacked GCC, generating a few database files
+    containing (among other data) the full call graph.
 
-The results will be in rootingHazards.txt
+3.  Then it runs `analyze.py`, a Python script, which runs all the scripts
+    which actually perform the analysis -- the tricky parts.
+    (Those scripts are written in JS.)
+
new file mode 100755
--- /dev/null
+++ b/js/src/devtools/rootAnalysis/run-analysis.sh
@@ -0,0 +1,85 @@
+# setup.sh - Run the rooting analysis on SpiderMonkey. See `README.txt` for usage.
+#
+# This script is based on the wiki page:
+# http://trac.wildfiregames.com/wiki/StaticRootingAnalysis
+
+set -eu
+
+BUILD_DIR="$PWD"
+ANALYSIS_SCRIPTDIR="$(dirname $0)"
+MOZILLA_SRCDIR="$(cd $ANALYSIS_SCRIPTDIR && (hg root || git rev-parse --show-toplevel))"
+
+
+# Requirements
+# ============
+#
+# Download and unpack the Sixgill plugin binaries.
+# (`wget -c` skips the download if you've already got the file.)
+#
+# This insecurely downloads software over HTTP. Sorry.
+#
+# The alternative is building your own Sixgill. That can be a pain and you may
+# need some patches to get it to work on your Linux distribution. Ask sfink for
+# details.
+
+mkdir -p downloads
+(cd downloads && wget -c http://people.mozilla.org/~sfink/data/hazards-sixgill.tar.xz)
+tar xf downloads/hazards-sixgill.tar.xz
+
+# Download and unpack GCC binaries compatible with the Sixgill plugin.
+(cd downloads && wget -c http://people.mozilla.org/~sfink/data/hazards-gcc4.7.tar.xz)
+tar xf downloads/hazards-gcc4.7.tar.xz
+
+
+# Generate raw data (.xdb files)
+# ==============================
+#
+# The first step is to generate the .xdb files that contain the information
+# needed by the analysis. This is done by compiling SpiderMonkey with the
+# sixgill plugin enabled. The plugin creates .xdb files which the analysis
+# consumes.
+
+PATH=$BUILD_DIR/sixgill/usr/bin:$PATH
+export PATH
+GCCDIR=$BUILD_DIR/gcc/bin
+export GCCDIR
+
+# Create a SpiderMonkey build directory and run configure.
+mkdir -p spidermonkey-analysis
+(cd spidermonkey-analysis && \
+    $MOZILLA_SRCDIR/js/src/configure --enable-optimize)
+
+# Make SpiderMonkey.
+$MOZILLA_SRCDIR/js/src/devtools/rootAnalysis/run_complete \
+    --build-root=$BUILD_DIR/spidermonkey-analysis \
+    --binaries=$BUILD_DIR/sixgill/usr/bin \
+    --wrap-dir=$BUILD_DIR/sixgill/usr/libexec/sixgill/scripts/wrap_gcc \
+    --buildcommand='make' \
+    --foreground \
+    --no-logs \
+    .
+
+
+# Run the analysis
+# ================
+
+# Build *another* copy of SpiderMonkey, using the system C++ compiler, without
+# Sixgill. This is what we use to run the analysis. (We don't let you skip this
+# step by setting a $JS environment variable or something, because you need
+# ctypes. Relax and spin a build.  Get yourself a cup of tea.)
+mkdir -p spidermonkey-opt
+(cd spidermonkey-opt && \
+    $MOZILLA_SRCDIR/js/src/configure --enable-optimize --enable-ctypes --enable-nspr-build && \
+    make -j8)
+JS="$BUILD_DIR/spidermonkey-opt/dist/bin/js"
+
+# Write a config file used by analyze.py.
+rm -f defaults.py
+echo "objdir = '${BUILD_DIR}/spidermonkey-analysis'" >> defaults.py
+echo "sixgill = '${BUILD_DIR}/sixgill/usr/libexec/sixgill'" >> defaults.py
+echo "sixgill_bin = '${BUILD_DIR}/sixgill/usr/bin'" >> defaults.py
+echo "js = '${JS}'" >> defaults.py
+echo "analysis_scriptdir = '${ANALYSIS_SCRIPTDIR}'" >> defaults.py
+
+# Run the script that runs the scripts that do the analysis.
+python2.7 "${MOZILLA_SRCDIR}/js/src/devtools/rootAnalysis/analyze.py" -j 8 callgraph
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -147,17 +147,17 @@ NativeRegExpMacroAssembler::GenerateCode
     frameSize = JS_ROUNDUP(frameSize + masm.framePushed(), ABIStackAlignment) - masm.framePushed();
 
     // Actually emit code to start a new stack frame.
     masm.reserveStack(frameSize);
     masm.checkStackAlignment();
 
     // Check if we have space on the stack.
     Label stack_ok;
-    void *stack_limit = runtime->mainThread.addressOfJitStackLimit();
+    void *stack_limit = runtime->addressOfJitStackLimit();
     masm.branchPtr(Assembler::Below, AbsoluteAddress(stack_limit), StackPointer, &stack_ok);
 
     // Exit with an exception. There is not enough space on the stack
     // for our working registers.
     masm.movePtr(ImmWord(RegExpRunStatus_Error), temp0);
     masm.jump(&return_temp0);
 
     masm.bind(&stack_ok);
@@ -257,17 +257,17 @@ NativeRegExpMacroAssembler::GenerateCode
                        ImmWord(register_offset(num_saved_registers_)), &init_loop);
     } else {
         // Unroll the loop.
         for (int i = 0; i < num_saved_registers_; i++)
             masm.storePtr(temp0, register_location(i));
     }
 
     // Initialize backtrack stack pointer.
-    masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), backtrack_stack_pointer);
+    masm.loadPtr(AbsoluteAddress(runtime->regexpStack.addressOfBase()), backtrack_stack_pointer);
     masm.storePtr(backtrack_stack_pointer, Address(StackPointer, offsetof(FrameData, backtrackStackBase)));
 
     masm.jump(&start_label_);
 
     // Exit code:
     if (success_label_.used()) {
         MOZ_ASSERT(num_saved_registers_ > 0);
 
@@ -417,17 +417,17 @@ NativeRegExpMacroAssembler::GenerateCode
         Label return_from_overflow_handler;
         masm.branchTest32(Assembler::Zero, temp0, temp0, &return_from_overflow_handler);
 
         // Otherwise, store the new backtrack stack base and recompute the new
         // top of the stack.
         Address backtrackStackBaseAddress(temp2, offsetof(FrameData, backtrackStackBase));
         masm.subPtr(backtrackStackBaseAddress, backtrack_stack_pointer);
 
-        masm.loadPtr(AbsoluteAddress(runtime->mainThread.regexpStack.addressOfBase()), temp1);
+        masm.loadPtr(AbsoluteAddress(runtime->regexpStack.addressOfBase()), temp1);
         masm.storePtr(temp1, backtrackStackBaseAddress);
         masm.addPtr(temp1, backtrack_stack_pointer);
 
         // Resume execution in calling code.
         masm.bind(&return_from_overflow_handler);
         masm.abiret();
     }
 
@@ -1045,17 +1045,17 @@ NativeRegExpMacroAssembler::PopBacktrack
     masm.loadPtr(Address(backtrack_stack_pointer, 0), target);
 }
 
 void
 NativeRegExpMacroAssembler::CheckBacktrackStackLimit()
 {
     JitSpew(SPEW_PREFIX "CheckBacktrackStackLimit");
 
-    const void *limitAddr = runtime->mainThread.regexpStack.addressOfLimit();
+    const void *limitAddr = runtime->regexpStack.addressOfLimit();
 
     Label no_stack_overflow;
     masm.branchPtr(Assembler::AboveOrEqual, AbsoluteAddress(limitAddr),
                    backtrack_stack_pointer, &no_stack_overflow);
 
     // Copy the stack pointer before the call() instruction modifies it.
     masm.movePtr(StackPointer, temp2);
 
--- a/js/src/irregexp/RegExpStack.cpp
+++ b/js/src/irregexp/RegExpStack.cpp
@@ -31,28 +31,28 @@
 #include "irregexp/RegExpStack.h"
 
 #include "vm/Runtime.h"
 
 using namespace js;
 using namespace js::irregexp;
 
 RegExpStackScope::RegExpStackScope(JSRuntime *rt)
-  : regexp_stack(&rt->mainThread.regexpStack)
+  : regexp_stack(&rt->regexpStack)
 {}
 
 RegExpStackScope::~RegExpStackScope()
 {
     regexp_stack->reset();
 }
 
 int
 irregexp::GrowBacktrackStack(JSRuntime *rt)
 {
-    return rt->mainThread.regexpStack.grow();
+    return rt->regexpStack.grow();
 }
 
 RegExpStack::RegExpStack()
   : base_(nullptr), size(0), limit_(nullptr)
 {}
 
 RegExpStack::~RegExpStack()
 {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/bug1122338.js
@@ -0,0 +1,38 @@
+// The bug was that the asm.js linker did not catch that an unshared
+// view was created on a shared buffer.  (Nor did it catch the vice
+// versa case.)  As a consequence the code was not rejected (and run
+// as plain JS) as it should be.  That gave rise to a difference in
+// output.
+
+// Original test
+
+g = (function(stdlib, n, heap) {
+    "use asm";
+    var Float32ArrayView = new stdlib.Float32Array(heap);
+    function f() {
+        return +Float32ArrayView[0]
+    }
+    return f
+})(this, {}, new SharedArrayBuffer(4096));
+assertEq(g(), NaN);
+
+// Additional test: vice versa case.
+
+try {
+    g = (function(stdlib, n, heap) {
+	"use asm";
+	var Float32ArrayView = new stdlib.SharedFloat32Array(heap);
+	function f() {
+            return +Float32ArrayView[0]
+	}
+	return f
+    })(this, {}, new ArrayBuffer(4096));
+    // If the code runs, as it would with the bug present, it must return NaN.
+    assertEq(g(), NaN);
+}
+catch (e) {
+    // If the code throws then that's OK too.  The current (January 2015)
+    // semantics is for the SharedFloat32Array constructor to throw if
+    // handed an ArrayBuffer, but asm.js does not execute that constructor
+    // and before the fix it would not throw.
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/resumption-error-01.js
@@ -0,0 +1,7 @@
+// A resumption value can't have both {return:} and {throw:} properties.
+
+var g = newGlobal();
+var dbg = Debugger(g);
+dbg.onDebuggerStatement = stack => ({return: 1, throw: 2});
+dbg.uncaughtExceptionHook = exc => ({return: "corrected"});
+assertEq(g.eval("debugger; false;"), "corrected");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/resumption-error-02.js
@@ -0,0 +1,16 @@
+// Error handling if parsing a resumption value throws.
+
+var g = newGlobal();
+var dbg = Debugger(g);
+var rv;
+dbg.onDebuggerStatement = stack => rv;
+dbg.uncaughtExceptionHook = function (exc) {
+    assertEq(exc, "BANG");
+    return {return: "recovered"};
+};
+
+rv = {get throw() { throw "BANG"; }};
+assertEq(g.eval("debugger; false;"), "recovered");
+
+rv = new Proxy({}, {has() { throw "BANG"; }});
+assertEq(g.eval("debugger; false;"), "recovered");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/simd-unbox.js
@@ -0,0 +1,108 @@
+if (typeof SIMD === "undefined")
+    quit();
+
+setJitCompilerOption("baseline.warmup.trigger", 10);
+setJitCompilerOption("ion.warmup.trigger", 30);
+var max = 40, pivot = 35;
+
+var i32x4 = SIMD.int32x4;
+var f32x4 = SIMD.float32x4;
+var i32x4Add = SIMD.int32x4.add;
+
+var FakeSIMDType = function (o) { this.x = o.x; this.y = o.y; this.z = o.z; this.w = o.w; };
+if (this.hasOwnProperty("TypedObject")) {
+  var TO = TypedObject;
+  FakeSIMDType = new TO.StructType({ x: TO.int32, y: TO.int32, z: TO.int32, w: TO.int32 });
+}
+
+
+function simdunbox_bail_undef(i, lhs, rhs) {
+  return i32x4Add(lhs, rhs);
+}
+
+function simdunbox_bail_object(i, lhs, rhs) {
+  return i32x4Add(lhs, rhs);
+}
+
+function simdunbox_bail_typeobj(i, lhs, rhs) {
+  return i32x4Add(lhs, rhs);
+}
+
+function simdunbox_bail_badsimd(i, lhs, rhs) {
+  return i32x4Add(lhs, rhs);
+}
+
+var arr_undef = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
+var fail_undef = 0;
+var arr_object = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
+var fail_object = 0;
+var arr_typeobj = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
+var fail_typeobj = 0;
+var arr_badsimd = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
+var fail_badsimd = 0;
+for (var i = 0; i < max; i++) {
+  try {
+    arr_undef[i + 2] = simdunbox_bail_undef(i, arr_undef[i], arr_undef[i + 1]);
+  } catch (x) {
+    arr_undef[i + 2] = arr_undef[i - 1];
+    fail_undef++;
+  }
+
+  try {
+    arr_object[i + 2] = simdunbox_bail_object(i, arr_object[i], arr_object[i + 1]);
+  } catch (x) {
+    arr_object[i + 2] = arr_object[i - 1];
+    fail_object++;
+  }
+
+  try {
+    arr_typeobj[i + 2] = simdunbox_bail_typeobj(i, arr_typeobj[i], arr_typeobj[i + 1]);
+  } catch (x) {
+    arr_typeobj[i + 2] = arr_typeobj[i - 1];
+    fail_typeobj++;
+  }
+
+  try {
+    arr_badsimd[i + 2] = simdunbox_bail_badsimd(i, arr_badsimd[i], arr_badsimd[i + 1]);
+  } catch (x) {
+    arr_badsimd[i + 2] = arr_badsimd[i - 1];
+    fail_badsimd++;
+  }
+
+  if (i + 2 == pivot) {
+    arr_undef[pivot] = undefined;
+    arr_object[pivot] = { x: 0, y: 1, z: 2, w: 3 };
+    arr_typeobj[pivot] = new FakeSIMDType({ x: 0, y: 1, z: 2, w: 3 });
+    arr_badsimd[pivot] = f32x4(0, 1, 2, 3);
+  }
+}
+
+assertEq(fail_undef, 2);
+assertEq(fail_object, 2);
+assertEq(fail_typeobj, 2);
+assertEq(fail_badsimd, 2);
+
+// Assert that all SIMD values are correct.
+function assertEqX4(real, expected, assertFunc) {
+    if (typeof assertFunc === 'undefined')
+        assertFunc = assertEq;
+
+    assertFunc(real.x, expected[0]);
+    assertFunc(real.y, expected[1]);
+    assertFunc(real.z, expected[2]);
+    assertFunc(real.w, expected[3]);
+}
+
+var fib = [0, 1];
+for (i = 0; i < max + 5; i++)
+  fib[i+2] = (fib[i] + fib[i+1]) | 0;
+
+for (i = 0; i < max; i++) {
+  if (i == pivot)
+    continue;
+  var ref = fib.slice(i < pivot ? i : i - 3);
+  assertEqX4(arr_undef[i], ref);
+  assertEqX4(arr_object[i], ref);
+  assertEqX4(arr_typeobj[i], ref);
+  assertEqX4(arr_badsimd[i], ref);
+}
--- a/js/src/jit-test/tests/ion/stack-alignment.js
+++ b/js/src/jit-test/tests/ion/stack-alignment.js
@@ -1,14 +1,36 @@
 setJitCompilerOption("baseline.warmup.trigger", 10);
 setJitCompilerOption("ion.warmup.trigger", 30);
 var i;
 
 // Check that an entry frame is always aligned properly.
 function entryFrame_1() {
-  assertValidJitStack();
+  assertJitStackInvariants();
+}
+
+// Check rectifier frames are keeping the same alignment.
+function rectifierFrame_verify(a, b, c, d) {
+  assertJitStackInvariants();
+}
+
+function rectifierFrame_1(i) {
+  rectifierFrame_verify();
+}
+function rectifierFrame_2(i) {
+  rectifierFrame_verify(i);
+}
+function rectifierFrame_3(i) {
+  rectifierFrame_verify(i, i);
+}
+function rectifierFrame_4(i) {
+  rectifierFrame_verify(i, i, i);
 }
 
 for (i = 0; i < 40; i++) {
   entryFrame_1();
   entryFrame_1(0);
   entryFrame_1(0, 1);
+  rectifierFrame_1(i);
+  rectifierFrame_2(i);
+  rectifierFrame_3(i);
+  rectifierFrame_4(i);
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited1.js
@@ -0,0 +1,16 @@
+// Getting a property that exists on an ordinary object
+// does not touch a proxy on its proto chain.
+
+load(libdir + "asserts.js");
+
+var angryHandler = new Proxy({}, {
+    get(t, id) { throw new Error("angryHandler should not be queried (" + id + ")"); }
+});
+var angryProto = new Proxy({}, angryHandler);
+var obj = Object.create(angryProto, {
+    x: {value: 3},
+    y: {get: () => 4}
+});
+assertThrowsInstanceOf(() => obj.z, Error);  // check that angryProto works
+assertEq(obj.x, 3);
+assertEq(obj.y, 4);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited2.js
@@ -0,0 +1,31 @@
+// Getting a property that's inherted from a proxy calls the proxy's get handler.
+
+var handler = {
+    get(t, id, r) {
+        assertEq(this, handler);
+        assertEq(t, target);
+        assertEq(id, "foo");
+        assertEq(r, obj);
+        return "bar";
+    },
+    getOwnPropertyDescriptor(t, id) {
+        throw "FAIL";
+    }
+};
+
+var target = {};
+var proto = new Proxy(target, handler);
+var obj = Object.create(proto);
+assertEq(obj.foo, "bar");
+
+// Longer proto chain: same result.
+var origObj = obj;
+for (var i = 0; i < 4; i++)
+    obj = Object.create(obj);
+assertEq(obj.foo, "bar");
+
+// Chain of transparent proxy wrappers: same result.
+obj = origObj;
+for (var i = 0; i < 4; i++)
+    obj = new Proxy(obj, {});
+assertEq(obj.foo, "bar");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited3.js
@@ -0,0 +1,21 @@
+// Recursion through the get hook works; runaway recursion is checked.
+
+load(libdir + "asserts.js");
+
+var hits = 0, limit = 10;
+var proto = new Proxy({}, {
+    get(t, id, r) {
+        assertEq(r, obj);
+        if (hits++ >= limit)
+            return "ding";
+        return obj[id];
+    }
+});
+
+var obj = Object.create(proto);
+assertEq(obj.prop, "ding");
+
+hits = 0;
+limit = Infinity;
+assertThrowsInstanceOf(() => obj.prop, InternalError);
+assertEq(hits > 10, true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testDirectProxyGetInherited4.js
@@ -0,0 +1,6 @@
+// A proxy P whose target is an object X whose prototype is an array V inherits V.length.
+
+var V = [1, 2, 3];
+var X = Object.create(V);
+var P = new Proxy(X, {});
+assertEq(P.length, 3);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/proxy/testWrapperGetInherited.js
@@ -0,0 +1,18 @@
+// Getting a property O.X, inherited from a transparent cross-compartment wrapper W
+// that wraps a Proxy P.
+
+var g = newGlobal();
+var target = {}
+var P = new Proxy(target, {
+    get(t, id, r) {
+        assertEq(t, target);
+        assertEq(id, "X");
+        assertEq(r, wO);
+        return "vega";
+    }
+});
+
+g.W = P;
+g.eval("var O = Object.create(W);");
+var wO = g.O;
+assertEq(g.eval("O.X"), "vega");
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -96,31 +96,44 @@ BacktrackingAllocator::go()
     if (!groupAndQueueRegisters())
         return false;
     JitSpew(JitSpew_RegAlloc, "Grouping and queueing registers complete");
 
     if (JitSpewEnabled(JitSpew_RegAlloc))
         dumpRegisterGroups();
 
     JitSpew(JitSpew_RegAlloc, "Beginning main allocation loop");
+
     // Allocate, spill and split register intervals until finished.
     while (!allocationQueue.empty()) {
         if (mir->shouldCancel("Backtracking Allocation"))
             return false;
 
         QueueItem item = allocationQueue.removeHighest();
         if (item.interval ? !processInterval(item.interval) : !processGroup(item.group))
             return false;
     }
     JitSpew(JitSpew_RegAlloc, "Main allocation loop complete");
 
+    if (!pickStackSlots())
+        return false;
+
     if (JitSpewEnabled(JitSpew_RegAlloc))
         dumpAllocations();
 
-    return resolveControlFlow() && reifyAllocations() && populateSafepoints();
+    if (!resolveControlFlow())
+        return false;
+
+    if (!reifyAllocations())
+        return false;
+
+    if (!populateSafepoints())
+        return false;
+
+    return true;
 }
 
 static bool
 LifetimesOverlap(BacktrackingVirtualRegister *reg0, BacktrackingVirtualRegister *reg1)
 {
     // Registers may have been eagerly split in two, see tryGroupReusedRegister.
     // In such cases, only consider the first interval.
     MOZ_ASSERT(reg0->numIntervals() <= 2 && reg1->numIntervals() <= 2);
@@ -378,16 +391,17 @@ BacktrackingAllocator::groupAndQueueRegi
 
         if (!reg.numIntervals())
             continue;
 
         // Eagerly set the canonical spill slot for registers which are fixed
         // for that slot, and reuse it for other registers in the group.
         LDefinition *def = reg.def();
         if (def->policy() == LDefinition::FIXED && !def->output()->isRegister()) {
+            MOZ_ASSERT(!def->output()->isStackSlot());
             reg.setCanonicalSpill(*def->output());
             if (reg.group() && reg.group()->spill.isUse())
                 reg.group()->spill = *def->output();
         }
 
         // Place all intervals for this register on the allocation queue.
         // During initial queueing use single queue items for groups of
         // registers, so that they will be allocated together and reduce the
@@ -925,31 +939,205 @@ BacktrackingAllocator::spill(LiveInterva
             JitSpew(JitSpew_RegAlloc, "    Reusing group spill location %s",
                     reg->group()->spill.toString());
             interval->setAllocation(reg->group()->spill);
             reg->setCanonicalSpill(reg->group()->spill);
             return;
         }
     }
 
-    uint32_t stackSlot = stackSlotAllocator.allocateSlot(reg->type());
-    MOZ_ASSERT(stackSlot <= stackSlotAllocator.stackHeight());
+    uint32_t virtualSlot = numVirtualStackSlots++;
 
-    LStackSlot alloc(stackSlot);
+    // Count virtual stack slots down from the maximum representable value, so
+    // that virtual slots are more obviously distinguished from real slots.
+    LStackSlot alloc(LAllocation::DATA_MASK - virtualSlot);
     interval->setAllocation(alloc);
 
     JitSpew(JitSpew_RegAlloc, "    Allocating spill location %s", alloc.toString());
 
     if (useCanonical) {
         reg->setCanonicalSpill(alloc);
         if (reg->group())
             reg->group()->spill = alloc;
     }
 }
 
+bool
+BacktrackingAllocator::pickStackSlots()
+{
+    for (size_t i = 1; i < graph.numVirtualRegisters(); i++) {
+        BacktrackingVirtualRegister *reg = &vregs[i];
+
+        if (mir->shouldCancel("Backtracking Pick Stack Slots"))
+            return false;
+
+        for (size_t j = 0; j < reg->numIntervals(); j++) {
+            LiveInterval *interval = reg->getInterval(j);
+            if (!pickStackSlot(interval))
+                return false;
+        }
+    }
+
+    return true;
+}
+
+bool
+BacktrackingAllocator::pickStackSlot(LiveInterval *interval)
+{
+    LAllocation alloc = *interval->getAllocation();
+    MOZ_ASSERT(!alloc.isUse());
+
+    if (!isVirtualStackSlot(alloc))
+        return true;
+
+    BacktrackingVirtualRegister &reg = vregs[interval->vreg()];
+
+    // Get a list of all the intervals which will share this stack slot.
+    LiveIntervalVector commonIntervals;
+
+    if (!commonIntervals.append(interval))
+        return false;
+
+    if (reg.canonicalSpill() && alloc == *reg.canonicalSpill()) {
+        // Look for other intervals in the vreg using this spill slot.
+        for (size_t i = 0; i < reg.numIntervals(); i++) {
+            LiveInterval *ninterval = reg.getInterval(i);
+            if (ninterval != interval && *ninterval->getAllocation() == alloc) {
+                if (!commonIntervals.append(ninterval))
+                    return false;
+            }
+        }
+
+        // Look for intervals in other registers with the same group using this
+        // spill slot.
+        if (reg.group() && alloc == reg.group()->spill) {
+            for (size_t i = 0; i < reg.group()->registers.length(); i++) {
+                uint32_t nvreg = reg.group()->registers[i];
+                if (nvreg == interval->vreg())
+                    continue;
+                BacktrackingVirtualRegister &nreg = vregs[nvreg];
+                for (size_t j = 0; j < nreg.numIntervals(); j++) {
+                    LiveInterval *ninterval = nreg.getInterval(j);
+                    if (*ninterval->getAllocation() == alloc) {
+                        if (!commonIntervals.append(ninterval))
+                            return false;
+                    }
+                }
+            }
+        }
+    } else {
+        MOZ_ASSERT_IF(reg.group(), alloc != reg.group()->spill);
+    }
+
+    if (!reuseOrAllocateStackSlot(commonIntervals, reg.type(), &alloc))
+        return false;
+
+    MOZ_ASSERT(!isVirtualStackSlot(alloc));
+
+    // Set the physical stack slot for each of the intervals found earlier.
+    for (size_t i = 0; i < commonIntervals.length(); i++)
+        commonIntervals[i]->setAllocation(alloc);
+
+    return true;
+}
+
+bool
+BacktrackingAllocator::reuseOrAllocateStackSlot(const LiveIntervalVector &intervals, LDefinition::Type type,
+                                                LAllocation *palloc)
+{
+    SpillSlotList *slotList;
+    switch (StackSlotAllocator::width(type)) {
+      case 4:  slotList = &normalSlots; break;
+      case 8:  slotList = &doubleSlots; break;
+      case 16: slotList = &quadSlots;   break;
+      default:
+        MOZ_CRASH("Bad width");
+    }
+
+    // Maximum number of existing spill slots we will look at before giving up
+    // and allocating a new slot.
+    static const size_t MAX_SEARCH_COUNT = 10;
+
+    if (!slotList->empty()) {
+        size_t searches = 0;
+        SpillSlot *stop = nullptr;
+        while (true) {
+            SpillSlot *spill = *slotList->begin();
+            if (!stop) {
+                stop = spill;
+            } else if (stop == spill) {
+                // We looked through every slot in the list.
+                break;
+            }
+
+            bool success = true;
+            for (size_t i = 0; i < intervals.length() && success; i++) {
+                LiveInterval *interval = intervals[i];
+                for (size_t j = 0; j < interval->numRanges(); j++) {
+                    AllocatedRange range(interval, interval->getRange(j)), existing;
+                    if (spill->allocated.contains(range, &existing)) {
+                        success = false;
+                        break;
+                    }
+                }
+            }
+            if (success) {
+                // We can reuse this physical stack slot for the new intervals.
+                // Update the allocated ranges for the slot.
+                if (!insertAllRanges(spill->allocated, intervals))
+                    return false;
+                *palloc = spill->alloc;
+                return true;
+            }
+
+            // On a miss, move the spill to the end of the list. This will cause us
+            // to make fewer attempts to allocate from slots with a large and
+            // highly contended range.
+            slotList->popFront();
+            slotList->pushBack(spill);
+
+            if (++searches == MAX_SEARCH_COUNT)
+                break;
+        }
+    }
+
+    // We need a new physical stack slot.
+    uint32_t stackSlot = stackSlotAllocator.allocateSlot(type);
+
+    // Make sure the virtual and physical stack slots don't start overlapping.
+    if (isVirtualStackSlot(LStackSlot(stackSlot)))
+        return false;
+
+    SpillSlot *spill = new(alloc()) SpillSlot(stackSlot, alloc().lifoAlloc());
+    if (!spill)
+        return false;
+
+    if (!insertAllRanges(spill->allocated, intervals))
+        return false;
+
+    *palloc = spill->alloc;
+
+    slotList->pushFront(spill);
+    return true;
+}
+
+bool
+BacktrackingAllocator::insertAllRanges(AllocatedRangeSet &set, const LiveIntervalVector &intervals)
+{
+    for (size_t i = 0; i < intervals.length(); i++) {
+        LiveInterval *interval = intervals[i];
+        for (size_t j = 0; j < interval->numRanges(); j++) {
+            AllocatedRange range(interval, interval->getRange(j));
+            if (!set.insert(range))
+                return false;
+        }
+    }
+    return true;
+}
+
 // Add moves to resolve conflicting assignments between a block and its
 // predecessors. XXX try to common this with LinearScanAllocator.
 bool
 BacktrackingAllocator::resolveControlFlow()
 {
     JitSpew(JitSpew_RegAlloc, "Resolving control flow (vreg loop)");
 
     // Virtual register number 0 is unused.
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -171,19 +171,38 @@ class BacktrackingAllocator
         PhysicalRegister() : allocatable(false) {}
     };
     mozilla::Array<PhysicalRegister, AnyRegister::Total> registers;
 
     // Ranges of code which are considered to be hot, for which good allocation
     // should be prioritized.
     AllocatedRangeSet hotcode;
 
+    // During register allocation, virtual stack slots are used for spills.
+    // These are converted to actual spill locations
+    size_t numVirtualStackSlots;
+
+    // Information about an allocated stack slot.
+    struct SpillSlot : public TempObject, public InlineForwardListNode<SpillSlot> {
+        LStackSlot alloc;
+        AllocatedRangeSet allocated;
+
+        SpillSlot(uint32_t slot, LifoAlloc *alloc)
+          : alloc(slot), allocated(alloc)
+        {}
+    };
+    typedef InlineForwardList<SpillSlot> SpillSlotList;
+
+    // All allocated slots of each width.
+    SpillSlotList normalSlots, doubleSlots, quadSlots;
+
   public:
     BacktrackingAllocator(MIRGenerator *mir, LIRGenerator *lir, LIRGraph &graph)
-      : LiveRangeAllocator<BacktrackingVirtualRegister, /* forLSRA = */ false>(mir, lir, graph)
+      : LiveRangeAllocator<BacktrackingVirtualRegister, /* forLSRA = */ false>(mir, lir, graph),
+        numVirtualStackSlots(0)
     { }
 
     bool go();
 
   private:
 
     typedef Vector<LiveInterval *, 4, SystemAllocPolicy> LiveIntervalVector;
 
@@ -208,17 +227,22 @@ class BacktrackingAllocator
     void spill(LiveInterval *interval);
 
     bool isReusedInput(LUse *use, LNode *ins, bool considerCopy);
     bool isRegisterUse(LUse *use, LNode *ins, bool considerCopy = false);
     bool isRegisterDefinition(LiveInterval *interval);
     bool addLiveInterval(LiveIntervalVector &intervals, uint32_t vreg,
                          LiveInterval *spillInterval,
                          CodePosition from, CodePosition to);
+    bool pickStackSlot(LiveInterval *interval);
+    bool reuseOrAllocateStackSlot(const LiveIntervalVector &intervals, LDefinition::Type type,
+                                  LAllocation *palloc);
+    bool insertAllRanges(AllocatedRangeSet &set, const LiveIntervalVector &intervals);
 
+    bool pickStackSlots();
     bool resolveControlFlow();
     bool reifyAllocations();
     bool populateSafepoints();
 
     void dumpRegisterGroups();
     void dumpFixedRanges();
     void dumpAllocations();
 
@@ -244,14 +268,19 @@ class BacktrackingAllocator
     bool trySplitAfterLastRegisterUse(LiveInterval *interval, LiveInterval *conflict, bool *success);
     bool trySplitBeforeFirstRegisterUse(LiveInterval *interval, LiveInterval *conflict, bool *success);
     bool splitAtAllRegisterUses(LiveInterval *interval);
     bool splitAcrossCalls(LiveInterval *interval);
 
     bool compilingAsmJS() {
         return mir->info().compilingAsmJS();
     }
+
+    bool isVirtualStackSlot(LAllocation alloc) {
+        return alloc.isStackSlot() &&
+               LAllocation::DATA_MASK - alloc.toStackSlot()->slot() < numVirtualStackSlots;
+    }
 };
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_BacktrackingAllocator_h */
--- a/js/src/jit/Bailouts.cpp
+++ b/js/src/jit/Bailouts.cpp
@@ -29,17 +29,17 @@ jit::Bailout(BailoutStack *sp, BaselineB
 {
     JSContext *cx = GetJSContextFromJitCode();
     MOZ_ASSERT(bailoutInfo);
 
     // We don't have an exit frame.
     MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
                IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
                "Fake jitTop pointer should be within the first page.");
-    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
+    cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, sp);
     JitFrameIterator iter(jitActivations);
     MOZ_ASSERT(!iter.ionScript()->invalidated());
     CommonFrameLayout *currentFramePtr = iter.current();
 
     TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
@@ -89,31 +89,31 @@ jit::Bailout(BailoutStack *sp, BaselineB
     // In the case of error, the jitcode will jump immediately to an
     // exception handler, which will unwind the frames and properly set
     // the |lastProfilingFrame| to point to the frame being resumed into
     // (see |AutoResetLastProfilerFrameOnReturnFromException|).
     //
     // In both cases, we want to temporarily set the |lastProfilingFrame|
     // to the current frame being bailed out, and then fix it up later.
     if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
-        cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
+        cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
 
     return retval;
 }
 
 uint32_t
 jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
                          BaselineBailoutInfo **bailoutInfo)
 {
     sp->checkInvariants();
 
     JSContext *cx = GetJSContextFromJitCode();
 
     // We don't have an exit frame.
-    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
+    cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, sp);
     JitFrameIterator iter(jitActivations);
     CommonFrameLayout *currentFramePtr = iter.current();
 
     TraceLoggerThread *logger = TraceLoggerForMainThread(cx->runtime());
     TraceLogTimestamp(logger, TraceLogger_Invalidation);
@@ -163,17 +163,17 @@ jit::InvalidationBailout(InvalidationBai
         JitSpew(JitSpew_IonInvalidate, "   new  frameSize %u", unsigned(frame->prevFrameLocalSize()));
         JitSpew(JitSpew_IonInvalidate, "   new  ra %p", (void *) frame->returnAddress());
     }
 
     iter.ionScript()->decrementInvalidationCount(cx->runtime()->defaultFreeOp());
 
     // Make the frame being bailed out the top profiled frame.
     if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
-        cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
+        cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
 
     return retval;
 }
 
 BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator &activations,
                                    const JitFrameIterator &frame)
   : machine_(frame.machineState())
 {
@@ -192,17 +192,17 @@ jit::ExceptionHandlerBailout(JSContext *
                              const ExceptionBailoutInfo &excInfo,
                              bool *overrecursed)
 {
     // We can be propagating debug mode exceptions without there being an
     // actual exception pending. For instance, when we return false from an
     // operation callback like a timeout handler.
     MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
 
-    cx->mainThread().jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
+    cx->runtime()->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
     gc::AutoSuppressGC suppress(cx);
 
     JitActivationIterator jitActivations(cx->runtime());
     BailoutFrameInfo bailoutData(jitActivations, frame.frame());
     JitFrameIterator iter(jitActivations);
     CommonFrameLayout *currentFramePtr = iter.current();
 
     BaselineBailoutInfo *bailoutInfo = nullptr;
@@ -233,17 +233,17 @@ jit::ExceptionHandlerBailout(JSContext *
         if (retval == BAILOUT_RETURN_OVERRECURSED)
             *overrecursed = true;
         else
             MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR);
     }
 
     // Make the frame being bailed out the top profiled frame.
     if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
-        cx->mainThread().jitActivation->setLastProfilingFrame(currentFramePtr);
+        cx->runtime()->jitActivation->setLastProfilingFrame(currentFramePtr);
 
     return retval;
 }
 
 // Initialize the decl env Object, call object, and any arguments obj of the current frame.
 bool
 jit::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
 {
--- a/js/src/jit/BaselineBailouts.cpp
+++ b/js/src/jit/BaselineBailouts.cpp
@@ -1649,17 +1649,17 @@ jit::FinishBailoutToBaseline(BaselineBai
     MOZ_ASSERT(cx->currentlyRunningInJit());
     JitFrameIterator iter(cx);
     uint8_t *outerFp = nullptr;
 
     // Iter currently points at the exit frame.  Get the previous frame
     // (which must be a baseline frame), and set it as the last profiling
     // frame.
     if (cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
-        cx->mainThread().jitActivation->setLastProfilingFrame(iter.prevFp());
+        cx->runtime()->jitActivation->setLastProfilingFrame(iter.prevFp());
 
     uint32_t frameno = 0;
     while (frameno < numFrames) {
         MOZ_ASSERT(!iter.isIonJS());
 
         if (iter.isBaselineJS()) {
             BaselineFrame *frame = iter.baselineFrame();
             MOZ_ASSERT(frame->script()->hasBaselineScript());
@@ -1702,17 +1702,17 @@ jit::FinishBailoutToBaseline(BaselineBai
     MOZ_ASSERT(innerScript);
     MOZ_ASSERT(outerScript);
     MOZ_ASSERT(outerFp);
 
     // If we rematerialized Ion frames due to debug mode toggling, copy their
     // values into the baseline frame. We need to do this even when debug mode
     // is off, as we should respect the mutations made while debug mode was
     // on.
-    JitActivation *act = cx->mainThread().activation()->asJit();
+    JitActivation *act = cx->runtime()->activation()->asJit();
     if (act->hasRematerializedFrame(outerFp)) {
         JitFrameIterator iter(cx);
         size_t inlineDepth = numFrames;
         while (inlineDepth > 0) {
             if (iter.isBaselineJS() &&
                 !CopyFromRematerializedFrame(cx, act, outerFp, --inlineDepth,
                                              iter.baselineFrame()))
             {
@@ -1749,16 +1749,18 @@ jit::FinishBailoutToBaseline(BaselineBai
       case Bailout_Hole:
       case Bailout_NegativeIndex:
       case Bailout_NonInt32Input:
       case Bailout_NonNumericInput:
       case Bailout_NonBooleanInput:
       case Bailout_NonObjectInput:
       case Bailout_NonStringInput:
       case Bailout_NonSymbolInput:
+      case Bailout_NonSimdInt32x4Input:
+      case Bailout_NonSimdFloat32x4Input:
       case Bailout_InitialState:
       case Bailout_Debugger:
         // Do nothing.
         break;
 
       // Invalid assumption based on baseline code.
       case Bailout_OverflowInvalidate:
       case Bailout_NonStringInputInvalidate:
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -507,17 +507,17 @@ BaselineCompiler::emitIC(ICStub *stub, I
 typedef bool (*CheckOverRecursedWithExtraFn)(JSContext *, BaselineFrame *, uint32_t, uint32_t);
 static const VMFunction CheckOverRecursedWithExtraInfo =
     FunctionInfo<CheckOverRecursedWithExtraFn>(CheckOverRecursedWithExtra);
 
 bool
 BaselineCompiler::emitStackCheck(bool earlyCheck)
 {
     Label skipCall;
-    void *limitAddr = cx->runtime()->mainThread.addressOfJitStackLimit();
+    void *limitAddr = cx->runtime()->addressOfJitStackLimit();
     uint32_t slotsSize = script->nslots() * sizeof(Value);
     uint32_t tolerance = earlyCheck ? slotsSize : 0;
 
     masm.movePtr(BaselineStackReg, R1.scratchReg());
 
     // If this is the early stack check, locals haven't been pushed yet.  Adjust the
     // stack pointer to account for the locals that would be pushed before performing
     // the guard around the vmcall to the stack check.
@@ -3639,17 +3639,17 @@ BaselineCompiler::emit_JSOP_RESUME()
 
     // If profiler instrumentation is on, update lastProfilingFrame on
     // current JitActivation
     {
         Register scratchReg = scratch2;
         Label skip;
         AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
         masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
-        masm.loadPtr(AbsoluteAddress(cx->mainThread().addressOfProfilingActivation()), scratchReg);
+        masm.loadPtr(AbsoluteAddress(cx->runtime()->addressOfProfilingActivation()), scratchReg);
         masm.storePtr(BaselineStackReg,
                       Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
         masm.bind(&skip);
     }
 
     // Construct BaselineFrame.
     masm.push(BaselineFrameReg);
     masm.mov(BaselineStackReg, BaselineFrameReg);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/TemplateLib.h"
 
 #include "jslibmath.h"
 #include "jstypes.h"
 
 #include "builtin/Eval.h"
+#include "builtin/SIMD.h"
 #include "jit/BaselineDebugModeOSR.h"
 #include "jit/BaselineHelpers.h"
 #include "jit/BaselineJIT.h"
 #include "jit/JitSpewer.h"
 #include "jit/Linker.h"
 #include "jit/Lowering.h"
 #ifdef JS_ION_PERF
 # include "jit/PerfSpewer.h"
@@ -1008,17 +1009,17 @@ ICWarmUpCounter_Fallback::Compiler::gene
 
 #ifdef DEBUG
     // If profiler instrumentation is on, ensure that lastProfilingFrame is
     // the frame currently being OSR-ed
     {
         Label checkOk;
         AbsoluteAddress addressOfEnabled(cx->runtime()->spsProfiler.addressOfEnabled());
         masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &checkOk);
-        masm.loadPtr(AbsoluteAddress((void*)&cx->mainThread().jitActivation), scratchReg);
+        masm.loadPtr(AbsoluteAddress((void*)&cx->runtime()->jitActivation), scratchReg);
         masm.loadPtr(Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()), scratchReg);
 
         // It may be the case that we entered the baseline frame with
         // profiling turned off on, then in a call within a loop (i.e. a
         // callee frame), turn on profiling, then return to this frame,
         // and then OSR with profiling turned on.  In this case, allow for
         // lastProfilingFrame to be null.
         masm.branchPtr(Assembler::Equal, scratchReg, Imm32(0), &checkOk);
@@ -8835,17 +8836,17 @@ TryAttachFunCallStub(JSContext *cx, ICCa
         return true;
     }
 
     return true;
 }
 
 static bool
 GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
-                           Native native, const CallArgs &args, MutableHandleNativeObject res)
+                           Native native, const CallArgs &args, MutableHandleObject res)
 {
     // Check for natives to which template objects can be attached. This is
     // done to provide templates to Ion for inlining these natives later on.
 
     if (native == js_Array) {
         // Note: the template array won't be used if its length is inaccurately
         // computed here.  (We allocate here because compilation may occur on a
         // separate thread where allocation is impossible.)
@@ -8912,16 +8913,24 @@ GetTemplateObjectForNative(JSContext *cx
     if (native == obj_create && args.length() == 1 && args[0].isObjectOrNull()) {
         RootedObject proto(cx, args[0].toObjectOrNull());
         res.set(ObjectCreateImpl(cx, proto, TenuredObject));
         if (!res)
             return false;
         return true;
     }
 
+    if (native == js::simd_int32x4_add && JitSupportsSimd()) {
+        Rooted<TypeDescr *> descr(cx, &Int32x4::GetTypeDescr(*cx->global()));
+        res.set(TypedObject::createZeroed(cx, descr, 0, gc::TenuredHeap));
+        if (!res)
+            return false;
+        return true;
+    }
+
     return true;
 }
 
 static bool
 GetTemplateObjectForClassHook(JSContext *cx, JSNative hook, CallArgs &args,
                               MutableHandleObject templateObject)
 {
     if (hook == TypedObject::construct) {
@@ -9146,17 +9155,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
             stub->addNewStub(newStub);
             return true;
         }
 
-        RootedNativeObject templateObject(cx);
+        RootedObject templateObject(cx);
         if (MOZ_LIKELY(!isSpread)) {
             CallArgs args = CallArgsFromVp(argc, vp);
             if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
                 return false;
         }
 
         JitSpew(JitSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s, spread=%s)",
                 fun.get(), constructing ? "yes" : "no", isSpread ? "yes" : "no");
@@ -11736,17 +11745,17 @@ ICCall_Scripted::Clone(JSContext *cx, IC
 /* static */ ICCall_AnyScripted *
 ICCall_AnyScripted::Clone(JSContext *, ICStubSpace *space, ICStub *firstMonitorStub,
                           ICCall_AnyScripted &other)
 {
     return New(space, other.jitCode(), firstMonitorStub, other.pcOffset_);
 }
 
 ICCall_Native::ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
-                             HandleFunction callee, HandleNativeObject templateObject,
+                             HandleFunction callee, HandleObject templateObject,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
     templateObject_(templateObject),
     pcOffset_(pcOffset)
 {
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     // The simulator requires VM calls to be redirected to a special swi
@@ -11757,17 +11766,17 @@ ICCall_Native::ICCall_Native(JitCode *st
 #endif
 }
 
 /* static */ ICCall_Native *
 ICCall_Native::Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                      ICCall_Native &other)
 {
     RootedFunction callee(cx, other.callee_);
-    RootedNativeObject templateObject(cx, other.templateObject_);
+    RootedObject templateObject(cx, other.templateObject_);
     return New(space, other.jitCode(), firstMonitorStub, callee, templateObject,
                other.pcOffset_);
 }
 
 ICCall_ClassHook::ICCall_ClassHook(JitCode *stubCode, ICStub *firstMonitorStub,
                                    const Class *clasp, Native native,
                                    HandleObject templateObject, uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_ClassHook, stubCode, firstMonitorStub),
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -5916,45 +5916,45 @@ class ICCallScriptedCompiler : public IC
 };
 
 class ICCall_Native : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected:
     HeapPtrFunction callee_;
-    HeapPtrNativeObject templateObject_;
+    HeapPtrObject templateObject_;
     uint32_t pcOffset_;
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     void *native_;
 #endif
 
     ICCall_Native(JitCode *stubCode, ICStub *firstMonitorStub,
-                  HandleFunction callee, HandleNativeObject templateObject,
+                  HandleFunction callee, HandleObject templateObject,
                   uint32_t pcOffset);
 
   public:
     static inline ICCall_Native *New(ICStubSpace *space, JitCode *code, ICStub *firstMonitorStub,
-                                     HandleFunction callee, HandleNativeObject templateObject,
+                                     HandleFunction callee, HandleObject templateObject,
                                      uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
         return space->allocate<ICCall_Native>(code, firstMonitorStub,
                                               callee, templateObject, pcOffset);
     }
 
     static ICCall_Native *Clone(JSContext *cx, ICStubSpace *space, ICStub *firstMonitorStub,
                                 ICCall_Native &other);
 
     HeapPtrFunction &callee() {
         return callee_;
     }
-    HeapPtrNativeObject &templateObject() {
+    HeapPtrObject &templateObject() {
         return templateObject_;
     }
 
     static size_t offsetOfCallee() {
         return offsetof(ICCall_Native, callee_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Native, pcOffset_);
@@ -5968,28 +5968,28 @@ class ICCall_Native : public ICMonitored
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
         bool isConstructing_;
         bool isSpread_;
         RootedFunction callee_;
-        RootedNativeObject templateObject_;
+        RootedObject templateObject_;
         uint32_t pcOffset_;
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16) |
                    (static_cast<int32_t>(isSpread_) << 17);
         }
 
       public:
         Compiler(JSContext *cx, ICStub *firstMonitorStub,
-                 HandleFunction callee, HandleNativeObject templateObject,
+                 HandleFunction callee, HandleObject templateObject,
                  bool isConstructing, bool isSpread, uint32_t pcOffset)
           : ICCallStubCompiler(cx, ICStub::Call_Native),
             firstMonitorStub_(firstMonitorStub),
             isConstructing_(isConstructing),
             isSpread_(isSpread),
             callee_(cx, callee),
             templateObject_(cx, templateObject),
             pcOffset_(pcOffset)
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -435,17 +435,17 @@ BaselineInspector::getTemplateObject(jsb
           default:
             break;
         }
     }
 
     return nullptr;
 }
 
-NativeObject *
+JSObject *
 BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
 {
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -105,17 +105,17 @@ class BaselineInspector
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenNegativeIndexGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
     bool hasSeenDoubleResult(jsbytecode *pc);
     bool hasSeenNonStringIterMore(jsbytecode *pc);
 
     NativeObject *getTemplateObject(jsbytecode *pc);
-    NativeObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
+    JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
     JSObject *getTemplateObjectForClassHook(jsbytecode *pc, const Class *clasp);
 
     DeclEnvObject *templateDeclEnvObject();
     CallObject *templateCallObject();
 
     JSObject *commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter,
                                     Shape **globalShape);
     JSObject *commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3070,35 +3070,27 @@ CodeGenerator::visitApplyArgsGeneric(LAp
         bailoutCmpPtr(Assembler::NotEqual, objreg, ptr, apply->snapshot());
     }
 
     // Copy the arguments of the current function.
     emitPushArguments(apply, copyreg);
 
     masm.checkStackAlignment();
 
-    // If the function is known to be uncompilable, only emit the call to InvokeFunction.
-    if (apply->hasSingleTarget()) {
-        JSFunction *target = apply->getSingleTarget();
-        if (target->isNative()) {
-            emitCallInvokeFunction(apply, copyreg);
-            emitPopArguments(apply, copyreg);
-            return;
-        }
+    // If the function is native, only emit the call to InvokeFunction.
+    if (apply->hasSingleTarget() && apply->getSingleTarget()->isNative()) {
+        emitCallInvokeFunction(apply, copyreg);
+        emitPopArguments(apply, copyreg);
+        return;
     }
 
     Label end, invoke;
 
-    // Guard that calleereg is an interpreted function with a JSScript:
-    if (!apply->hasSingleTarget()) {
-        masm.branchIfFunctionHasNoScript(calleereg, &invoke);
-    } else {
-        // Native single targets are handled by LCallNative.
-        MOZ_ASSERT(!apply->getSingleTarget()->isNative());
-    }
+    // Guard that calleereg is an interpreted function with a JSScript.
+    masm.branchIfFunctionHasNoScript(calleereg, &invoke);
 
     // Knowing that calleereg is a non-native function, load the JSScript.
     masm.loadPtr(Address(calleereg, JSFunction::offsetOfNativeOrScript()), objreg);
 
     // Load script jitcode.
     masm.loadBaselineOrIonRaw(objreg, objreg, &invoke);
 
     // Call with an Ion frame or a rectifier frame.
@@ -4228,16 +4220,84 @@ CodeGenerator::visitSimdBox(LSimdBox *li
       case MIRType_Float32x4:
         masm.storeUnalignedFloat32x4(in, objectData);
         break;
       default:
         MOZ_CRASH("Unknown SIMD kind when generating code for SimdBox.");
     }
 }
 
+void
+CodeGenerator::visitSimdUnbox(LSimdUnbox *lir)
+{
+    Register object = ToRegister(lir->input());
+    FloatRegister simd = ToFloatRegister(lir->output());
+    Register temp = ToRegister(lir->temp());
+    Label bail;
+
+    // obj->type()
+    masm.loadPtr(Address(object, JSObject::offsetOfType()), temp);
+
+    // Guard that the object has the same representation as the one produced for
+    // SIMD value-type.
+    Address clasp(temp, types::TypeObject::offsetOfClasp());
+    static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
+    masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
+                   &bail);
+
+    // obj->type()->typeDescr()
+    // The previous class pointer comparison implies that the addendumKind is
+    // Addendum_TypeDescr.
+    masm.loadPtr(Address(temp, types::TypeObject::offsetOfAddendum()), temp);
+
+    // Check for the /Kind/ reserved slot of the TypeDescr.  This is an Int32
+    // Value which is equivalent to the object class check.
+    static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
+    Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
+    masm.assertTestInt32(Assembler::Equal, typeDescrKind,
+      "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
+    masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
+
+    // Convert the SIMD MIRType to a SimdTypeDescr::Type.
+    js::SimdTypeDescr::Type type;
+    switch (lir->mir()->type()) {
+      case MIRType_Int32x4:
+        type = js::SimdTypeDescr::TYPE_INT32;
+        break;
+      case MIRType_Float32x4:
+        type = js::SimdTypeDescr::TYPE_FLOAT32;
+        break;
+      default:
+        MOZ_CRASH("Unexpected SIMD Type.");
+    }
+
+    // Check if the SimdTypeDescr /Type/ match the specialization of this
+    // MSimdUnbox instruction.
+    static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
+    Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
+    masm.assertTestInt32(Assembler::Equal, typeDescrType,
+      "MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
+    masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(type), &bail);
+
+    // Load the value from the data of the InlineTypedObject.
+    Address objectData(object, InlineTypedObject::offsetOfDataStart());
+    switch (lir->mir()->type()) {
+      case MIRType_Int32x4:
+        masm.loadUnalignedInt32x4(objectData, simd);
+        break;
+      case MIRType_Float32x4:
+        masm.loadUnalignedFloat32x4(objectData, simd);
+        break;
+      default:
+        MOZ_CRASH("The impossible happened!");
+    }
+
+    bailoutFrom(&bail, lir->snapshot());
+}
+
 typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction, gc::InitialHeap);
 static const VMFunction NewDeclEnvObjectInfo =
     FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
 
 void
 CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
 {
     Register objReg = ToRegister(lir->output());
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -151,16 +151,17 @@ class CodeGenerator : public CodeGenerat
     void visitOutOfLineNewArray(OutOfLineNewArray *ool);
     void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite *lir);
     void visitNewArrayDynamicLength(LNewArrayDynamicLength *lir);
     void visitNewObjectVMCall(LNewObject *lir);
     void visitNewObject(LNewObject *lir);
     void visitOutOfLineNewObject(OutOfLineNewObject *ool);
     void visitNewTypedObject(LNewTypedObject *lir);
     void visitSimdBox(LSimdBox *lir);
+    void visitSimdUnbox(LSimdUnbox *lir);
     void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     void visitNewCallObject(LNewCallObject *lir);
     void visitNewSingletonCallObject(LNewSingletonCallObject *lir);
     void visitNewStringObject(LNewStringObject *lir);
     void visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
     void visitInitElem(LInitElem *lir);
     void visitInitElemGetterSetter(LInitElemGetterSetter *lir);
     void visitMutateProto(LMutateProto *lir);
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -32,47 +32,47 @@ CompileRuntime::mainThread()
 {
     MOZ_ASSERT(onMainThread());
     return &runtime()->mainThread;
 }
 
 const void *
 CompileRuntime::addressOfJitTop()
 {
-    return &runtime()->mainThread.jitTop;
+    return &runtime()->jitTop;
 }
 
 const void *
 CompileRuntime::addressOfJitActivation()
 {
-    return &runtime()->mainThread.jitActivation;
+    return &runtime()->jitActivation;
 }
 
 const void *
 CompileRuntime::addressOfProfilingActivation()
 {
-    return (const void *) &runtime()->mainThread.profilingActivation_;
+    return (const void *) &runtime()->profilingActivation_;
 }
 
 const void *
 CompileRuntime::addressOfJitStackLimit()
 {
-    return runtime()->mainThread.addressOfJitStackLimit();
+    return runtime()->addressOfJitStackLimit();
 }
 
 const void *
 CompileRuntime::addressOfJSContext()
 {
-    return &runtime()->mainThread.jitJSContext;
+    return &runtime()->jitJSContext;
 }
 
 const void *
 CompileRuntime::addressOfActivation()
 {
-    return runtime()->mainThread.addressOfActivation();
+    return runtime()->addressOfActivation();
 }
 
 const void *
 CompileRuntime::addressOfLastCachedNativeIterator()
 {
     return &runtime()->nativeIterCache.last;
 }
 
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -26,32 +26,32 @@ class CompileRuntime
 
   public:
     static CompileRuntime *get(JSRuntime *rt);
 
     bool onMainThread();
 
     js::PerThreadData *mainThread();
 
-    // &mainThread.jitTop
+    // &runtime()->jitTop
     const void *addressOfJitTop();
 
-    // &mainThread.jitActivation
+    // &runtime()->jitActivation
     const void *addressOfJitActivation();
 
-    // &mainThread.profilingActivation
+    // &runtime()->profilingActivation
     const void *addressOfProfilingActivation();
 
-    // rt->mainThread.jitStackLimit;
+    // rt->runtime()->jitStackLimit;
     const void *addressOfJitStackLimit();
 
-    // &mainThread.jitJSContext
+    // &runtime()->jitJSContext
     const void *addressOfJSContext();
 
-    // &mainThread.activation_
+    // &runtime()->activation_
     const void *addressOfActivation();
 
     // &GetJitContext()->runtime->nativeIterCache.last
     const void *addressOfLastCachedNativeIterator();
 
 #ifdef JS_GC_ZEAL
     const void *addressOfGCZeal();
 #endif
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -783,17 +783,21 @@ class IonBuilder
     InliningStatus inlineTypedArrayLength(CallInfo &callInfo);
 
     // TypedObject intrinsics and natives.
     InliningStatus inlineObjectIsTypeDescr(CallInfo &callInfo);
     InliningStatus inlineSetTypedObjectOffset(CallInfo &callInfo);
     bool elementAccessIsTypedObjectArrayOfScalarType(MDefinition* obj, MDefinition* id,
                                                      ScalarTypeDescr::Type *arrayType);
     InliningStatus inlineConstructTypedObject(CallInfo &callInfo, TypeDescr *target);
+
+    // SIMD intrinsics and natives.
     InliningStatus inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *target);
+    InliningStatus inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
+                                                MSimdBinaryArith::Operation op);
 
     // Utility intrinsics.
     InliningStatus inlineIsCallable(CallInfo &callInfo);
     InliningStatus inlineIsObject(CallInfo &callInfo);
     InliningStatus inlineToObject(CallInfo &callInfo);
     InliningStatus inlineToInteger(CallInfo &callInfo);
     InliningStatus inlineToString(CallInfo &callInfo);
     InliningStatus inlineDump(CallInfo &callInfo);
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -95,16 +95,20 @@ enum BailoutKind
     // Unbox expects a given type, bails out if it doesn't get it.
     Bailout_NonInt32Input,
     Bailout_NonNumericInput, // unboxing a double works with int32 too
     Bailout_NonBooleanInput,
     Bailout_NonObjectInput,
     Bailout_NonStringInput,
     Bailout_NonSymbolInput,
 
+    // SIMD Unbox expects a given type, bails out if it doesn't match.
+    Bailout_NonSimdInt32x4Input,
+    Bailout_NonSimdFloat32x4Input,
+
     // For the initial snapshot when entering a function.
     Bailout_InitialState,
 
     // We hit a |debugger;| statement.
     Bailout_Debugger,
 
     // END Normal bailouts
 
@@ -188,16 +192,20 @@ BailoutKindString(BailoutKind kind)
       case Bailout_NonBooleanInput:
         return "Bailout_NonBooleanInput";
       case Bailout_NonObjectInput:
         return "Bailout_NonObjectInput";
       case Bailout_NonStringInput:
         return "Bailout_NonStringInput";
       case Bailout_NonSymbolInput:
         return "Bailout_NonSymbolInput";
+      case Bailout_NonSimdInt32x4Input:
+        return "Bailout_NonSimdInt32x4Input";
+      case Bailout_NonSimdFloat32x4Input:
+        return "Bailout_NonSimdFloat32x4Input";
       case Bailout_InitialState:
         return "Bailout_InitialState";
       case Bailout_Debugger:
         return "Bailout_Debugger";
 
       // Bailouts caused by invalid assumptions.
       case Bailout_OverflowInvalidate:
         return "Bailout_OverflowInvalidate";
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -84,18 +84,19 @@ class CommonFrameLayout;
 class JitFrameLayout;
 class ExitFrameLayout;
 
 class BaselineFrame;
 
 class JitActivation;
 
 // Iterate over the JIT stack to assert that all invariants are respected.
-//  - Check that all entry frames are aligned on StackAlignment.
-void AssertValidJitStack(JSContext *cx);
+//  - Check that all entry frames are aligned on JitStackAlignment.
+//  - Check that all rectifier frames keep the JitStackAlignment.
+void AssertJitStackInvariants(JSContext *cx);
 
 class JitFrameIterator
 {
   protected:
     uint8_t *current_;
     FrameType type_;
     uint8_t *returnAddressToFp_;
     size_t frameSize_;
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -93,22 +93,22 @@ JitFrameIterator::JitFrameIterator()
     returnAddressToFp_(nullptr),
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
     activation_(nullptr)
 {
 }
 
 JitFrameIterator::JitFrameIterator(JSContext *cx)
-  : current_(cx->perThreadData->jitTop),
+  : current_(cx->runtime()->jitTop),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
-    activation_(cx->perThreadData->activation()->asJit())
+    activation_(cx->runtime()->activation()->asJit())
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
         frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
     }
 }
 
@@ -385,17 +385,17 @@ HandleExceptionIon(JSContext *cx, const 
     jsbytecode *pc = frame.pc();
 
     if (cx->compartment()->isDebuggee()) {
         // We need to bail when there is a catchable exception, and we are the
         // debuggee of a Debugger with a live onExceptionUnwind hook, or if a
         // Debugger has observed this frame (e.g., for onPop).
         bool shouldBail = Debugger::hasLiveHook(cx->global(), Debugger::OnExceptionUnwind);
         if (!shouldBail) {
-            JitActivation *act = cx->mainThread().activation()->asJit();
+            JitActivation *act = cx->runtime()->activation()->asJit();
             RematerializedFrame *rematFrame =
                 act->lookupRematerializedFrame(frame.frame().fp(), frame.frameNo());
             shouldBail = rematFrame && rematFrame->isDebuggee();
         }
 
         if (shouldBail) {
             // If we have an exception from within Ion and the debugger is active,
             // we do the following:
@@ -688,20 +688,20 @@ struct AutoResetLastProfilerFrameOnRetur
 
     AutoResetLastProfilerFrameOnReturnFromException(JSContext *cx, ResumeFromException *rfe)
       : cx(cx), rfe(rfe) {}
 
     ~AutoResetLastProfilerFrameOnReturnFromException() {
         if (!cx->runtime()->jitRuntime()->isProfilerInstrumentationEnabled(cx->runtime()))
             return;
 
-        MOZ_ASSERT(cx->mainThread().jitActivation == cx->mainThread().profilingActivation());
+        MOZ_ASSERT(cx->runtime()->jitActivation == cx->runtime()->profilingActivation());
 
         void *lastProfilingFrame = getLastProfilingFrame();
-        cx->mainThread().jitActivation->setLastProfilingFrame(lastProfilingFrame);
+        cx->runtime()->jitActivation->setLastProfilingFrame(lastProfilingFrame);
     }
 
     void *getLastProfilingFrame() {
         switch (rfe->kind) {
           case ResumeFromException::RESUME_ENTRY_FRAME:
             return nullptr;
 
           // The following all return into baseline frames.
@@ -735,17 +735,17 @@ HandleException(ResumeFromException *rfe
 
     // Clear any Ion return override that's been set.
     // This may happen if a callVM function causes an invalidation (setting the
     // override), and then fails, bypassing the bailout handlers that would
     // otherwise clear the return override.
     if (cx->runtime()->jitRuntime()->hasIonReturnOverride())
         cx->runtime()->jitRuntime()->takeIonReturnOverride();
 
-    JitActivation *activation = cx->mainThread().activation()->asJit();
+    JitActivation *activation = cx->runtime()->activation()->asJit();
 
     // The Debugger onExceptionUnwind hook (reachable via
     // HandleExceptionBaseline below) may cause on-stack recompilation of
     // baseline scripts, which may patch return addresses on the stack. Since
     // JitFrameIterators cache the previous frame's return address when
     // iterating, we need a variant here that is automatically updated should
     // on-stack recompilation occur.
     DebugModeOSRVolatileJitFrameIterator iter(cx);
@@ -858,17 +858,17 @@ HandleException(ResumeFromException *rfe
 
         if (current) {
             // Unwind the frame by updating jitTop. This is necessary so that
             // (1) debugger exception unwind and leave frame hooks don't see this
             // frame when they use ScriptFrameIter, and (2) ScriptFrameIter does
             // not crash when accessing an IonScript that's destroyed by the
             // ionScript->decref call.
             EnsureExitFrame(current);
-            cx->mainThread().jitTop = (uint8_t *)current;
+            cx->runtime()->jitTop = (uint8_t *)current;
         }
 
         if (overrecursed) {
             // We hit an overrecursion error during bailout. Report it now.
             js_ReportOverRecursed(cx);
         }
     }
 
@@ -2732,26 +2732,26 @@ JitFrameIterator::verifyReturnAddressUsi
 }
 #endif // DEBUG
 
 JitProfilingFrameIterator::JitProfilingFrameIterator(
         JSRuntime *rt, const JS::ProfilingFrameIterator::RegisterState &state)
 {
     // If no profilingActivation is live, initialize directly to
     // end-of-iteration state.
-    if (!rt->mainThread.profilingActivation()) {
+    if (!rt->profilingActivation()) {
         type_ = JitFrame_Entry;
         fp_ = nullptr;
         returnAddressToFp_ = nullptr;
         return;
     }
 
-    MOZ_ASSERT(rt->mainThread.profilingActivation()->isJit());
-
-    JitActivation *act = rt->mainThread.profilingActivation()->asJit();
+    MOZ_ASSERT(rt->profilingActivation()->isJit());
+
+    JitActivation *act = rt->profilingActivation()->asJit();
 
     // If the top JitActivation has a null lastProfilingFrame, assume that
     // it's a trivially empty activation, and initialize directly
     // to end-of-iteration state.
     if (!act->lastProfilingFrame()) {
         type_ = JitFrame_Entry;
         fp_ = nullptr;
         returnAddressToFp_ = nullptr;
@@ -3021,22 +3021,40 @@ InvalidationBailoutStack::checkInvariant
     uint8_t *rawBase = ionScript()->method()->raw();
     uint8_t *rawLimit = rawBase + ionScript()->method()->instructionsSize();
     uint8_t *osiPoint = osiPointReturnAddress();
     MOZ_ASSERT(rawBase <= osiPoint && osiPoint <= rawLimit);
 #endif
 }
 
 void
-AssertValidJitStack(JSContext *cx)
+AssertJitStackInvariants(JSContext *cx)
 {
     for (JitActivationIterator activations(cx->runtime()); !activations.done(); ++activations) {
         JitFrameIterator frames(activations);
-        for (; !frames.done(); ++frames)
-            continue;
+        for (; !frames.done(); ++frames) {
+
+            if (frames.prevType() == JitFrame_Rectifier) {
+                size_t calleeFp = reinterpret_cast<size_t>(frames.fp());
+                size_t callerFp = reinterpret_cast<size_t>(frames.prevFp());
+                MOZ_ASSERT(callerFp >= calleeFp);
+                size_t frameSize = callerFp - calleeFp;
+
+                MOZ_RELEASE_ASSERT(frameSize % JitStackAlignment == 0,
+                  "The rectifier frame should keep the alignment");
+
+                size_t expectedFrameSize = 0
+                    + sizeof(Value) * (frames.callee()->nargs() + 1 /* |this| argument */ )
+                    + sizeof(JitFrameLayout);
+                MOZ_RELEASE_ASSERT(frameSize >= expectedFrameSize,
+                  "The frame is large enough to hold all arguments");
+                MOZ_RELEASE_ASSERT(expectedFrameSize + JitStackAlignment > frameSize,
+                  "The frame size is optimal");
+            }
+        }
 
         MOZ_RELEASE_ASSERT(frames.type() == JitFrame_Entry,
           "The first frame of a Jit activation should be an entry frame");
         MOZ_RELEASE_ASSERT(reinterpret_cast<size_t>(frames.fp()) % JitStackAlignment == 0,
           "The entry frame should be properly aligned");
     }
 }
 
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -152,16 +152,36 @@ class LSimdBox : public LInstructionHelp
         return getTemp(0);
     }
 
     MSimdBox *mir() const {
         return mir_->toSimdBox();
     }
 };
 
+class LSimdUnbox : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(SimdUnbox)
+
+    LSimdUnbox(const LAllocation &obj, const LDefinition &temp)
+    {
+        setOperand(0, obj);
+        setTemp(0, temp);
+    }
+
+    const LDefinition *temp() {
+        return getTemp(0);
+    }
+
+    MSimdUnbox *mir() const {
+        return mir_->toSimdUnbox();
+    }
+};
+
 // Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4).
 class LSimdSplatX4 : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(SimdSplatX4)
     explicit LSimdSplatX4(const LAllocation &v)
     {
         setOperand(0, v);
--- a/js/src/jit/LIR.h
+++ b/js/src/jit/LIR.h
@@ -62,29 +62,30 @@ class LAllocation : public TempObject
     // 8-byte aligned.
     static const uintptr_t KIND_BITS = 3;
     static const uintptr_t KIND_SHIFT = 0;
     static const uintptr_t KIND_MASK = (1 << KIND_BITS) - 1;
 
   protected:
     static const uintptr_t DATA_BITS = (sizeof(uint32_t) * 8) - KIND_BITS;
     static const uintptr_t DATA_SHIFT = KIND_SHIFT + KIND_BITS;
-    static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
 
   public:
     enum Kind {
         CONSTANT_VALUE, // Constant js::Value.
         CONSTANT_INDEX, // Constant arbitrary index.
         USE,            // Use of a virtual register, with physical allocation policy.
         GPR,            // General purpose register.
         FPU,            // Floating-point register.
         STACK_SLOT,     // Stack slot.
         ARGUMENT_SLOT   // Argument slot.
     };
 
+    static const uintptr_t DATA_MASK = (1 << DATA_BITS) - 1;
+
   protected:
     uint32_t data() const {
         return uint32_t(bits_) >> DATA_SHIFT;
     }
     void setData(uint32_t data) {
         MOZ_ASSERT(data <= DATA_MASK);
         bits_ &= ~(DATA_MASK << DATA_SHIFT);
         bits_ |= (data << DATA_SHIFT);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -13,16 +13,17 @@
     _(Mop)                          \
     _(OsiPoint)                     \
     _(MoveGroup)                    \
     _(Integer)                      \
     _(Pointer)                      \
     _(Double)                       \
     _(Float32)                      \
     _(SimdBox)                      \
+    _(SimdUnbox)                    \
     _(SimdSplatX4)                  \
     _(Int32x4)                      \
     _(Float32x4)                    \
     _(SimdExtractElementI)          \
     _(SimdExtractElementF)          \
     _(SimdInsertElementI)           \
     _(SimdInsertElementF)           \
     _(SimdSignMaskX4)               \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3730,16 +3730,40 @@ LIRGenerator::visitSimdBox(MSimdBox *ins
     LUse in = useRegister(ins->input());
     LSimdBox *lir = new(alloc()) LSimdBox(in, temp());
     // :TODO: Cannot spill SIMD registers (Bug 1112164)
     assignSnapshot(lir, Bailout_Inevitable);
     define(lir, ins);
 }
 
 void
+LIRGenerator::visitSimdUnbox(MSimdUnbox *ins)
+{
+    MOZ_ASSERT(ins->input()->type() == MIRType_Object);
+    MOZ_ASSERT(IsSimdType(ins->type()));
+    LUse in = useRegister(ins->input());
+
+    BailoutKind kind;
+    switch (ins->type()) {
+      case MIRType_Int32x4:
+        kind = Bailout_NonSimdInt32x4Input;
+        break;
+      case MIRType_Float32x4:
+        kind = Bailout_NonSimdFloat32x4Input;
+        break;
+      default:
+        MOZ_CRASH("Unexpected SIMD Type.");
+    };
+
+    LSimdUnbox *lir = new(alloc()) LSimdUnbox(in, temp());
+    assignSnapshot(lir, kind);
+    define(lir, ins);
+}
+
+void
 LIRGenerator::visitSimdConstant(MSimdConstant *ins)
 {
     MOZ_ASSERT(IsSimdType(ins->type()));
 
     if (ins->type() == MIRType_Int32x4)
         define(new(alloc()) LInt32x4(), ins);
     else if (ins->type() == MIRType_Float32x4)
         define(new(alloc()) LFloat32x4(), ins);
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -261,16 +261,17 @@ class LIRGenerator : public LIRGenerator
     void visitAsmJSPassStackArg(MAsmJSPassStackArg *ins);
     void visitAsmJSCall(MAsmJSCall *ins);
     void visitSetDOMProperty(MSetDOMProperty *ins);
     void visitGetDOMProperty(MGetDOMProperty *ins);
     void visitGetDOMMember(MGetDOMMember *ins);
     void visitRecompileCheck(MRecompileCheck *ins);
     void visitMemoryBarrier(MMemoryBarrier *ins);
     void visitSimdBox(MSimdBox *ins);
+    void visitSimdUnbox(MSimdUnbox *ins);
     void visitSimdExtractElement(MSimdExtractElement *ins);
     void visitSimdInsertElement(MSimdInsertElement *ins);
     void visitSimdSignMask(MSimdSignMask *ins);
     void visitSimdSwizzle(MSimdSwizzle *ins);
     void visitSimdShuffle(MSimdShuffle *ins);
     void visitSimdUnaryArith(MSimdUnaryArith *ins);
     void visitSimdBinaryComp(MSimdBinaryComp *ins);
     void visitSimdBinaryBitwise(MSimdBinaryBitwise *ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsmath.h"
 
 #include "builtin/AtomicsObject.h"
+#include "builtin/SIMD.h"
 #include "builtin/TestingFunctions.h"
 #include "builtin/TypedObject.h"
 #include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "vm/ArgumentsObject.h"
@@ -241,16 +242,20 @@ IonBuilder::inlineNativeCall(CallInfo &c
         return inlineBailout(callInfo);
     if (native == testingFunc_assertFloat32)
         return inlineAssertFloat32(callInfo);
 
     // Bound function
     if (native == js::CallOrConstructBoundFunction)
         return inlineBoundFunction(callInfo, target);
 
+    // Simd functions
+    if (native == js::simd_int32x4_add)
+        return inlineSimdInt32x4BinaryArith(callInfo, native, MSimdBinaryArith::Add);
+
     return InliningStatus_NotInlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineNativeGetter(CallInfo &callInfo, JSFunction *target)
 {
     MOZ_ASSERT(target->isNative());
     JSNative native = target->native();
@@ -344,56 +349,55 @@ IonBuilder::inlineMathFunction(CallInfo 
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineArray(CallInfo &callInfo)
 {
     uint32_t initLength = 0;
     AllocatingBehaviour allocating = NewArray_Unallocating;
 
-    NativeObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
+    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
     if (!templateObject)
         return InliningStatus_NotInlined;
-    MOZ_ASSERT(templateObject->is<ArrayObject>());
+    ArrayObject *templateArray = &templateObject->as<ArrayObject>();
 
     // Multiple arguments imply array initialization, not just construction.
     if (callInfo.argc() >= 2) {
         initLength = callInfo.argc();
         allocating = NewArray_FullyAllocating;
 
-        types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
+        types::TypeObjectKey *type = types::TypeObjectKey::get(templateArray);
         if (!type->unknownProperties()) {
             types::HeapTypeSetKey elemTypes = type->property(JSID_VOID);
 
             for (uint32_t i = 0; i < initLength; i++) {
                 MDefinition *value = callInfo.getArg(i);
                 if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
                     elemTypes.freeze(constraints());
                     return InliningStatus_NotInlined;
                 }
             }
         }
     }
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         getInlineReturnTypeSet()->convertDoubleElements(constraints());
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
-        templateObject->setShouldConvertDoubleElements();
+        templateArray->setShouldConvertDoubleElements();
     else
-        templateObject->clearShouldConvertDoubleElements();
+        templateArray->clearShouldConvertDoubleElements();
 
     // A single integer argument denotes initial length.
     if (callInfo.argc() == 1) {
         if (callInfo.getArg(0)->type() != MIRType_Int32)
             return InliningStatus_NotInlined;
 
         MDefinition *arg = callInfo.getArg(0);
         if (!arg->isConstantValue()) {
             callInfo.setImplicitlyUsedUnchecked();
-            ArrayObject *templateArray = &templateObject->as<ArrayObject>();
             MNewArrayDynamicLength *ins =
                 MNewArrayDynamicLength::New(alloc(), constraints(), templateArray,
                                             templateArray->type()->initialHeap(constraints()),
                                             arg);
             current->add(ins);
             current->push(ins);
             return InliningStatus_Inlined;
         }
@@ -401,33 +405,33 @@ IonBuilder::inlineArray(CallInfo &callIn
         // Negative lengths generate a RangeError, unhandled by the inline path.
         initLength = arg->constantValue().toInt32();
         if (initLength >= NativeObject::NELEMENTS_LIMIT)
             return InliningStatus_NotInlined;
 
         // Make sure initLength matches the template object's length. This is
         // not guaranteed to be the case, for instance if we're inlining the
         // MConstant may come from an outer script.
-        if (initLength != templateObject->as<ArrayObject>().length())
+        if (initLength != templateArray->as<ArrayObject>().length())
             return InliningStatus_NotInlined;
 
         // Don't inline large allocations.
         if (initLength > ArrayObject::EagerAllocationMaxLength)
             return InliningStatus_NotInlined;
 
         allocating = NewArray_FullyAllocating;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
+    MConstant *templateConst = MConstant::NewConstraintlessObject(alloc(), templateArray);
     current->add(templateConst);
 
     MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
-                                    templateObject->type()->initialHeap(constraints()),
+                                    templateArray->type()->initialHeap(constraints()),
                                     allocating);
     current->add(ins);
     current->push(ins);
 
     if (callInfo.argc() >= 2) {
         // Get the elements vector.
         MElements *elements = MElements::New(alloc(), ins);
         current->add(elements);
@@ -725,17 +729,17 @@ IonBuilder::inlineArrayConcat(CallInfo &
             return InliningStatus_NotInlined;
 
         types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID);
         if (!elemTypes.knownSubset(constraints(), thisElemTypes))
             return InliningStatus_NotInlined;
     }
 
     // Inline the call.
-    NativeObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
+    JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
     if (!templateObj || templateObj->type() != baseThisType)
         return InliningStatus_NotInlined;
     MOZ_ASSERT(templateObj->is<ArrayObject>());
 
     callInfo.setImplicitlyUsedUnchecked();
 
     MArrayConcat *ins = MArrayConcat::New(alloc(), constraints(), callInfo.thisArg(), callInfo.getArg(0),
                                           &templateObj->as<ArrayObject>(),
@@ -1606,17 +1610,17 @@ IonBuilder::inlineSubstringKernel(CallIn
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineObjectCreate(CallInfo &callInfo)
 {
     if (callInfo.argc() != 1 || callInfo.constructing())
         return InliningStatus_NotInlined;
 
-    NativeObject *templateObject = inspector->getTemplateObjectForNative(pc, obj_create);
+    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, obj_create);
     if (!templateObject)
         return InliningStatus_NotInlined;
 
     MOZ_ASSERT(templateObject->is<PlainObject>());
     MOZ_ASSERT(!templateObject->hasSingletonType());
 
     // Ensure the argument matches the template object's prototype.
     MDefinition *arg = callInfo.getArg(0);
@@ -2608,10 +2612,42 @@ IonBuilder::inlineConstructSimdObject(Ca
                                   inlineTypedObject->type()->initialHeap(constraints()));
     current->add(obj);
     current->push(obj);
 
     callInfo.setImplicitlyUsedUnchecked();
     return InliningStatus_Inlined;
 }
 
+IonBuilder::InliningStatus
+IonBuilder::inlineSimdInt32x4BinaryArith(CallInfo &callInfo, JSNative native,
+                                         MSimdBinaryArith::Operation op)
+{
+    if (callInfo.argc() != 2)
+        return InliningStatus_NotInlined;
+
+    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
+    if (!templateObject)
+        return InliningStatus_NotInlined;
+
+    InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
+    MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == js::Int32x4::type);
+
+    // If the type of any of the arguments is neither a SIMD type, an Object
+    // type, or a Value, then the applyTypes phase will add a fallible box &
+    // unbox sequence.  This does not matter much as the binary arithmetic
+    // instruction is supposed to produce a TypeError once it is called.
+    MSimdBinaryArith *ins = MSimdBinaryArith::New(alloc(), callInfo.getArg(0), callInfo.getArg(1),
+                                                  op, MIRType_Int32x4);
+
+    MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
+                                  inlineTypedObject->type()->initialHeap(constraints()));
+
+    current->add(ins);
+    current->add(obj);
+    current->push(obj);
+
+    callInfo.setImplicitlyUsedUnchecked();
+    return InliningStatus_Inlined;
+}
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -1917,17 +1917,17 @@ class MSimdBinaryComp
         return operation_ == ins->toSimdBinaryComp()->operation();
     }
 
     ALLOW_CLONE(MSimdBinaryComp)
 };
 
 class MSimdBinaryArith
   : public MBinaryInstruction,
-    public NoTypePolicy::Data
+    public MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >::Data
 {
   public:
     enum Operation {
         Add,
         Sub,
         Mul,
         Div,
         Min,
@@ -1953,30 +1953,36 @@ class MSimdBinaryArith
   private:
     Operation operation_;
 
     MSimdBinaryArith(MDefinition *left, MDefinition *right, Operation op, MIRType type)
       : MBinaryInstruction(left, right), operation_(op)
     {
         MOZ_ASSERT_IF(type == MIRType_Int32x4, op == Add || op == Sub || op == Mul);
         MOZ_ASSERT(IsSimdType(type));
-        MOZ_ASSERT(left->type() == right->type());
-        MOZ_ASSERT(left->type() == type);
         setResultType(type);
         setMovable();
         if (op == Add || op == Mul || op == Min || op == Max)
             setCommutative();
     }
 
   public:
     INSTRUCTION_HEADER(SimdBinaryArith)
+    static MSimdBinaryArith *New(TempAllocator &alloc, MDefinition *left, MDefinition *right,
+                                 Operation op, MIRType t)
+    {
+        return new(alloc) MSimdBinaryArith(left, right, op, t);
+    }
+
     static MSimdBinaryArith *NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right,
                                       Operation op, MIRType t)
     {
-        return new(alloc) MSimdBinaryArith(left, right, op, t);
+        MOZ_ASSERT(left->type() == right->type());
+        MOZ_ASSERT(left->type() == t);
+        return New(alloc, left, right, op, t);
     }
 
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
 
     Operation operation() const { return operation_; }
 
@@ -2979,16 +2985,43 @@ class MSimdBox
         return false;
     }
 
     AliasSet getAliasSet() const MOZ_OVERRIDE {
         return AliasSet::None();
     }
 };
 
+class MSimdUnbox
+  : public MUnaryInstruction,
+    public SingleObjectPolicy::Data
+{
+  protected:
+    MSimdUnbox(MDefinition *op, MIRType type)
+      : MUnaryInstruction(op)
+    {
+        MOZ_ASSERT(IsSimdType(type));
+        setMovable();
+        setResultType(type);
+    }
+
+  public:
+    INSTRUCTION_HEADER(SimdUnbox)
+    ALLOW_CLONE(MSimdUnbox)
+
+    static MSimdUnbox *New(TempAllocator &alloc, MDefinition *op, MIRType type)
+    {
+        return new(alloc) MSimdUnbox(op, type);
+    }
+
+    AliasSet getAliasSet() const MOZ_OVERRIDE {
+        return AliasSet::None();
+    }
+};
+
 // Creates a new derived type object. At runtime, this is just a call
 // to `BinaryBlock::createDerived()`. That is, the MIR itself does not
 // compile to particularly optimized code. However, using a distinct
 // MIR for creating derived type objects allows the compiler to
 // optimize ephemeral typed objects as would be created for a
 // reference like `a.b.c` -- here, the `a.b` will create an ephemeral
 // derived type object that aliases the memory of `a` itself. The
 // specific nature of `a.b` is revealed by using
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -8,16 +8,17 @@
 #define jit_MOpcodes_h
 
 namespace js {
 namespace jit {
 
 #define MIR_OPCODE_LIST(_)                                                  \
     _(Constant)                                                             \
     _(SimdBox)                                                              \
+    _(SimdUnbox)                                                            \
     _(SimdValueX4)                                                          \
     _(SimdSplatX4)                                                          \
     _(SimdConstant)                                                         \
     _(SimdConvert)                                                          \
     _(SimdReinterpretCast)                                                  \
     _(SimdExtractElement)                                                   \
     _(SimdInsertElement)                                                    \
     _(SimdSignMask)                                                         \
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -1351,16 +1351,30 @@ MacroAssembler::assumeUnreachable(const 
 
         PopRegsInMask(RegisterSet::Volatile());
     }
 #endif
 
     breakpoint();
 }
 
+template<typename T>
+void
+MacroAssembler::assertTestInt32(Condition cond, const T &value, const char *output)
+{
+#ifdef DEBUG
+    Label ok;
+    branchTestInt32(cond, value, &ok);
+    assumeUnreachable(output);
+    bind(&ok);
+#endif
+}
+
+template void MacroAssembler::assertTestInt32(Condition, const Address &, const char *);
+
 static void
 Printf0_(const char *output) {
     // Use stderr instead of stdout because this is only used for debug
     // output. stderr is less likely to interfere with the program's normal
     // output, and it's always unbuffered.
     fprintf(stderr, "%s", output);
 }
 
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -971,16 +971,20 @@ class MacroAssembler : public MacroAssem
     Label *failureLabel() {
         return &failureLabel_;
     }
 
     void finish();
     void link(JitCode *code);
 
     void assumeUnreachable(const char *output);
+
+    template<typename T>
+    void assertTestInt32(Condition cond, const T &value, const char *output);
+
     void printf(const char *output);
     void printf(const char *output, Register value);
 
 #ifdef JS_TRACE_LOGGING
     void tracelogStartId(Register logger, uint32_t textId, bool force = false);
     void tracelogStartId(Register logger, Register textId);
     void tracelogStartEvent(Register logger, Register event);
     void tracelogStopId(Register logger, uint32_t textId, bool force = false);
--- a/js/src/jit/Snapshots.cpp
+++ b/js/src/jit/Snapshots.cpp
@@ -14,20 +14,48 @@
 # include "jit/LIR.h"
 #endif
 #include "jit/MIR.h"
 #include "jit/Recover.h"
 
 using namespace js;
 using namespace js::jit;
 
+// Encodings:
+//   [ptr] A fixed-size pointer.
+//   [vwu] A variable-width unsigned integer.
+//   [vws] A variable-width signed integer.
+//    [u8] An 8-bit unsigned integer.
+//   [u8'] An 8-bit unsigned integer which is potentially extended with packed
+//         data.
+//   [u8"] Packed data which is stored and packed in the previous [u8'].
+//  [vwu*] A list of variable-width unsigned integers.
+//   [pld] Payload of Recover Value Allocation:
+//         PAYLOAD_NONE:
+//           There is no payload.
+//
+//         PAYLOAD_INDEX:
+//           [vwu] Index, such as the constant pool index.
+//
+//         PAYLOAD_STACK_OFFSET:
+//           [vws] Stack offset based on the base of the Ion frame.
+//
+//         PAYLOAD_GPR:
+//            [u8] Code of the general register.
+//
+//         PAYLOAD_FPU:
+//            [u8] Code of the FPU register.
+//
+//         PAYLOAD_PACKED_TAG:
+//           [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
+//                           of the RValueAllocation.
+//
 // Snapshot header:
 //
-//   [vwu] bits ((n+1)-31]: frame count
-//         bit n+1: resume after
+//   [vwu] bits ((n+1)-31]: recover instruction offset
 //         bits [0,n): bailout kind (n = SNAPSHOT_BAILOUTKIND_BITS)
 //
 // Snapshot body, repeated "frame count" times, from oldest frame to newest frame.
 // Note that the first frame doesn't have the "parent PC" field.
 //
 //   [ptr] Debug only: JSScript *
 //   [vwu] pc offset
 //   [vwu] # of RVA's indexes, including nargs
@@ -87,45 +115,16 @@ using namespace js::jit;
 //         TYPED_REG [PACKED_TAG, GPR_REG]:
 //           Value with statically known type, which payload is stored in a
 //           register.
 //
 //         TYPED_STACK [PACKED_TAG, STACK_OFFSET]:
 //           Value with statically known type, which payload is stored at an
 //           offset on the stack.
 //
-// Encodings:
-//   [ptr] A fixed-size pointer.
-//   [vwu] A variable-width unsigned integer.
-//   [vws] A variable-width signed integer.
-//    [u8] An 8-bit unsigned integer.
-//   [u8'] An 8-bit unsigned integer which is potentially extended with packed
-//         data.
-//   [u8"] Packed data which is stored and packed in the previous [u8'].
-//  [vwu*] A list of variable-width unsigned integers.
-//   [pld] Payload of Recover Value Allocation:
-//         PAYLOAD_NONE:
-//           There is no payload.
-//
-//         PAYLOAD_INDEX:
-//           [vwu] Index, such as the constant pool index.
-//
-//         PAYLOAD_STACK_OFFSET:
-//           [vws] Stack offset based on the base of the Ion frame.
-//
-//         PAYLOAD_GPR:
-//            [u8] Code of the general register.
-//
-//         PAYLOAD_FPU:
-//            [u8] Code of the FPU register.
-//
-//         PAYLOAD_PACKED_TAG:
-//           [u8"] Bits 5-7: JSValueType is encoded on the low bits of the Mode
-//                           of the RValueAllocation.
-//
 
 const RValueAllocation::Layout &
 RValueAllocation::layoutFromMode(Mode mode)
 {
     switch (mode) {
       case CONSTANT: {
         static const RValueAllocation::Layout layout = {
             PAYLOAD_INDEX,
@@ -493,17 +492,17 @@ SnapshotReader::SnapshotReader(const uin
     readSnapshotHeader();
 }
 
 #define COMPUTE_SHIFT_AFTER_(name) (name ## _BITS + name ##_SHIFT)
 #define COMPUTE_MASK_(name) ((uint32_t(1 << name ## _BITS) - 1) << name ##_SHIFT)
 
 // Details of snapshot header packing.
 static const uint32_t SNAPSHOT_BAILOUTKIND_SHIFT = 0;
-static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 5;
+static const uint32_t SNAPSHOT_BAILOUTKIND_BITS = 6;
 static const uint32_t SNAPSHOT_BAILOUTKIND_MASK = COMPUTE_MASK_(SNAPSHOT_BAILOUTKIND);
 
 static const uint32_t SNAPSHOT_ROFFSET_SHIFT = COMPUTE_SHIFT_AFTER_(SNAPSHOT_BAILOUTKIND);
 static const uint32_t SNAPSHOT_ROFFSET_BITS = 32 - SNAPSHOT_ROFFSET_SHIFT;
 static const uint32_t SNAPSHOT_ROFFSET_MASK = COMPUTE_MASK_(SNAPSHOT_ROFFSET);
 
 // Details of recover header packing.
 static const uint32_t RECOVER_RESUMEAFTER_SHIFT = 0;
--- a/js/src/jit/StackSlotAllocator.h
+++ b/js/src/jit/StackSlotAllocator.h
@@ -70,70 +70,60 @@ class StackSlotAllocator
         }
         return height_ += 4;
     }
 
   public:
     StackSlotAllocator() : height_(0)
     { }
 
-    void freeSlot(LDefinition::Type type, uint32_t index) {
+    static uint32_t width(LDefinition::Type type) {
         switch (type) {
 #if JS_BITS_PER_WORD == 32
           case LDefinition::GENERAL:
           case LDefinition::OBJECT:
           case LDefinition::SLOTS:
 #endif
           case LDefinition::INT32:
-          case LDefinition::FLOAT32:   return freeSlot(index);
+          case LDefinition::FLOAT32:   return 4;
 #if JS_BITS_PER_WORD == 64
           case LDefinition::GENERAL:
           case LDefinition::OBJECT:
           case LDefinition::SLOTS:
 #endif
 #ifdef JS_PUNBOX64
           case LDefinition::BOX:
 #endif
 #ifdef JS_NUNBOX32
           case LDefinition::TYPE:
           case LDefinition::PAYLOAD:
 #endif
-          case LDefinition::DOUBLE:    return freeDoubleSlot(index);
+          case LDefinition::DOUBLE:    return 8;
           case LDefinition::FLOAT32X4:
-          case LDefinition::INT32X4:   return freeQuadSlot(index);
+          case LDefinition::INT32X4:   return 16;
         }
         MOZ_CRASH("Unknown slot type");
     }
 
+    void freeSlot(LDefinition::Type type, uint32_t index) {
+        switch (width(type)) {
+          case 4:  return freeSlot(index);
+          case 8:  return freeDoubleSlot(index);
+          case 16: return freeQuadSlot(index);
+        }
+        MOZ_CRASH("Unknown slot width");
+    }
+
     uint32_t allocateSlot(LDefinition::Type type) {
-        switch (type) {
-#if JS_BITS_PER_WORD == 32
-          case LDefinition::GENERAL:
-          case LDefinition::OBJECT:
-          case LDefinition::SLOTS:
-#endif
-          case LDefinition::INT32:
-          case LDefinition::FLOAT32:   return allocateSlot();
-#if JS_BITS_PER_WORD == 64
-          case LDefinition::GENERAL:
-          case LDefinition::OBJECT:
-          case LDefinition::SLOTS:
-#endif
-#ifdef JS_PUNBOX64
-          case LDefinition::BOX:
-#endif
-#ifdef JS_NUNBOX32
-          case LDefinition::TYPE:
-          case LDefinition::PAYLOAD:
-#endif
-          case LDefinition::DOUBLE:    return allocateDoubleSlot();
-          case LDefinition::FLOAT32X4:
-          case LDefinition::INT32X4:   return allocateQuadSlot();
+        switch (width(type)) {
+          case 4:  return allocateSlot();
+          case 8:  return allocateDoubleSlot();
+          case 16: return allocateQuadSlot();
         }
-        MOZ_CRASH("Unknown slot type");
+        MOZ_CRASH("Unknown slot width");
     }
 
     uint32_t stackHeight() const {
         return height_;
     }
 };
 
 } // namespace jit
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -712,16 +712,39 @@ ObjectPolicy<Op>::staticAdjustInputs(Tem
     return replace->typePolicy()->adjustInputs(alloc, replace);
 }
 
 template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
 
+template <unsigned Op>
+bool
+SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
+{
+    MIRType type = ins->type();
+    MOZ_ASSERT(IsSimdType(type));
+
+    MDefinition *in = ins->getOperand(Op);
+    if (in->type() == type)
+        return true;
+
+    MSimdUnbox *replace = MSimdUnbox::New(alloc, in, type);
+    ins->block()->insertBefore(ins, replace);
+    ins->replaceOperand(Op, replace);
+
+    return replace->typePolicy()->adjustInputs(alloc, replace);
+}
+
+template bool
+SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
+template bool
+SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
+
 bool
 CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
 {
     MCall *call = ins->toCall();
 
     MDefinition *func = call->getFunction();
     if (func->type() != MIRType_Object) {
         MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible);
@@ -1037,16 +1060,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(MixPolicy<ObjectPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1> >)                    \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2> >)                    \
     _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3> >)                    \
     _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, StringPolicy<1> >)                     \
     _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2> >)            \
     _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0> >)            \
+    _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdSameAsReturnedTypePolicy<1> >) \
     _(MixPolicy<StringPolicy<0>, IntPolicy<1> >)                        \
     _(MixPolicy<StringPolicy<0>, StringPolicy<1> >)                     \
     _(NoFloatPolicy<0>)                                                 \
     _(NoFloatPolicyAfter<1>)                                            \
     _(NoFloatPolicyAfter<2>)                                            \
     _(ObjectPolicy<0>)                                                  \
     _(ObjectPolicy<1>)                                                  \
     _(ObjectPolicy<3>)                                                  \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -312,16 +312,29 @@ class SimdScalarPolicy MOZ_FINAL : publi
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, def);
     }
 };
 
+// SIMD value-type policy, use the returned type of the instruction to determine
+// how to unbox its operand.
+template <unsigned Op>
+class SimdSameAsReturnedTypePolicy MOZ_FINAL : public TypePolicy
+{
+  public:
+    EMPTY_DATA_;
+    static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
+    virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
+        return staticAdjustInputs(alloc, ins);
+    }
+};
+
 template <unsigned Op>
 class BoxPolicy MOZ_FINAL : public TypePolicy
 {
   public:
     EMPTY_DATA_;
     static bool staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
     virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE {
         return staticAdjustInputs(alloc, ins);
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -772,17 +772,17 @@ DebugEpilogue(JSContext *cx, BaselineFra
     }
 
     if (!ok) {
         // Pop this frame by updating jitTop, so that the exception handling
         // code will start at the previous frame.
 
         JitFrameLayout *prefix = frame->framePrefix();
         EnsureExitFrame(prefix);
-        cx->mainThread().jitTop = (uint8_t *)prefix;
+        cx->runtime()->jitTop = (uint8_t *)prefix;
         return false;
     }
 
     // Clear the override pc. This is not necessary for correctness: the frame
     // will return immediately, but this simplifies the check we emit in debug
     // builds after each callVM, to ensure this flag is not set.
     frame->clearOverridePc();
     return true;
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -33,23 +33,26 @@ class MacroAssemblerARM : public Assembl
   protected:
     // On ARM, some instructions require a second scratch register. This
     // register defaults to lr, since it's non-allocatable (as it can be
     // clobbered by some instructions). Allow the baseline compiler to override
     // this though, since baseline IC stubs rely on lr holding the return
     // address.
     Register secondScratchReg_;
 
+  public:
     // Higher level tag testing code.
     Operand ToPayload(Operand base) {
         return Operand(Register::FromCode(base.base()), base.disp());
     }
     Address ToPayload(Address base) {
         return ToPayload(Operand(base)).toAddress();
     }
+
+  protected:
     Operand ToType(Operand base) {
         return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *));
     }
     Address ToType(Address base) {
         return ToType(Operand(base)).toAddress();
     }
 
   public:
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -4221,17 +4221,17 @@ Simulator::execute()
                 single_step_callback_(single_step_callback_arg_, this, (void*)program_counter);
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
             icount_++;
 
             int32_t rpc = resume_pc_;
             if (MOZ_UNLIKELY(rpc != 0)) {
                 // AsmJS signal handler ran and we have to adjust the pc.
-                PerThreadData::innermostAsmJSActivation()->setResumePC((void *)get_pc());
+                JSRuntime::innermostAsmJSActivation()->setResumePC((void *)get_pc());
                 set_pc(rpc);
                 resume_pc_ = 0;
             }
         }
         program_counter = get_pc();
     }
 
     if (single_stepping_)
@@ -4413,40 +4413,52 @@ Simulator::Current()
 
     return sim;
 }
 
 } // namespace jit
 } // namespace js
 
 js::jit::Simulator *
+JSRuntime::simulator() const
+{
+    return simulator_;
+}
+
+js::jit::Simulator *
 js::PerThreadData::simulator() const
 {
-    return simulator_;
+    return runtime_->simulator();
+}
+
+void
+JSRuntime::setSimulator(js::jit::Simulator *sim)
+{
+    simulator_ = sim;
+    simulatorStackLimit_ = sim->stackLimit();
 }
 
 void
 js::PerThreadData::setSimulator(js::jit::Simulator *sim)
 {
-    simulator_ = sim;
-    simulatorStackLimit_ = sim->stackLimit();
+    runtime_->setSimulator(sim);
+}
+
+uintptr_t *
+JSRuntime::addressOfSimulatorStackLimit()
+{
+    return &simulatorStackLimit_;
 }
 
 js::jit::SimulatorRuntime *
 js::PerThreadData::simulatorRuntime() const
 {
     return runtime_->simulatorRuntime();
 }
 
-uintptr_t *
-js::PerThreadData::addressOfSimulatorStackLimit()
-{
-    return &simulatorStackLimit_;
-}
-
 js::jit::SimulatorRuntime *
 JSRuntime::simulatorRuntime() const
 {
     return simulatorRuntime_;
 }
 
 void
 JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -372,17 +372,17 @@ class Simulator
     int64_t icount() {
         return icount_;
     }
 
 };
 
 #define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror)             \
     JS_BEGIN_MACRO                                                              \
-        if (cx->mainThread().simulator()->overRecursedWithExtra(extra)) {       \
+        if (cx->runtime()->simulator()->overRecursedWithExtra(extra)) {         \
             js_ReportOverRecursed(cx);                                          \
             onerror;                                                            \
         }                                                                       \
     JS_END_MACRO
 
 } // namespace jit
 } // namespace js
 
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -62,22 +62,23 @@ static const ValueOperand JSReturnOperan
 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
 
 static Register CallReg = t9;
 static const int defaultShift = 3;
 static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong");
 
 class MacroAssemblerMIPS : public Assembler
 {
-  protected:
+  public:
     // higher level tag testing code
     Operand ToPayload(Operand base);
     Address ToPayload(Address base) {
         return ToPayload(Operand(base)).toAddress();
     }
+  protected:
     Operand ToType(Operand base);
     Address ToType(Address base) {
         return ToType(Operand(base)).toAddress();
     }
 
   public:
 
     void convertBoolToInt32(Register source, Register dest);
--- a/js/src/jit/mips/Simulator-mips.cpp
+++ b/js/src/jit/mips/Simulator-mips.cpp
@@ -3307,17 +3307,17 @@ Simulator::branchDelayInstructionDecode(
 
 template<bool enableStopSimAt>
 void
 Simulator::execute()
 {
     // Get the PC to simulate. Cannot use the accessor here as we need the
     // raw PC value and not the one used as input to arithmetic instructions.
     int program_counter = get_pc();
-    AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStack();
+    AsmJSActivation *activation = TlsPerThreadData.get()->runtimeFromMainThread()->asmJSActivationStack();
 
     while (program_counter != end_sim_pc) {
         if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
             MipsDebugger dbg(this);
             dbg.debug();
         } else {
             SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
             instructionDecode(instr);
@@ -3465,40 +3465,52 @@ Simulator::popAddress()
     setRegister(sp, current_sp + sizeof(uintptr_t));
     return address;
 }
 
 } // namespace jit
 } // namespace js
 
 js::jit::Simulator *
+JSRuntime::simulator() const
+{
+    return simulator_;
+}
+
+js::jit::Simulator *
 js::PerThreadData::simulator() const
 {
-    return simulator_;
+    return runtime_->simulator();
+}
+
+void
+JSRuntime::setSimulator(js::jit::Simulator *sim)
+{
+    simulator_ = sim;
+    simulatorStackLimit_ = sim->stackLimit();
 }
 
 void
 js::PerThreadData::setSimulator(js::jit::Simulator *sim)
 {
-    simulator_ = sim;
-    simulatorStackLimit_ = sim->stackLimit();
+    runtime_->setSimulator(sim);
+}
+
+uintptr_t *
+JSRuntime::addressOfSimulatorStackLimit()
+{
+    return &simulatorStackLimit_;
 }
 
 js::jit::SimulatorRuntime *
 js::PerThreadData::simulatorRuntime() const
 {
     return runtime_->simulatorRuntime();
 }
 
-uintptr_t *
-js::PerThreadData::addressOfSimulatorStackLimit()
-{
-    return &simulatorStackLimit_;
-}
-
 js::jit::SimulatorRuntime *
 JSRuntime::simulatorRuntime() const
 {
     return simulatorRuntime_;
 }
 
 void
 JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -156,16 +156,20 @@ class MacroAssemblerX64 : public MacroAs
 
     JSValueShiftedTag GetShiftedTag(JSValueType type) {
         return (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
     }
 
     /////////////////////////////////////////////////////////////////
     // X86/X64-common interface.
     /////////////////////////////////////////////////////////////////
+    Address ToPayload(Address value) {
+        return value;
+    }
+
     void storeValue(ValueOperand val, Operand dest) {
         movq(val.valueReg(), dest);
     }
     void storeValue(ValueOperand val, const Address &dest) {
         storeValue(val, Operand(dest));
     }
     template <typename T>
     void storeValue(JSValueType type, Register reg, const T &dest) {
--- a/js/src/jit/x64/Trampoline-x64.cpp
+++ b/js/src/jit/x64/Trampoline-x64.cpp
@@ -375,61 +375,101 @@ JitRuntime::generateInvalidator(JSContex
 }
 
 JitCode *
 JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
 {
     // Do not erase the frame pointer in this function.
 
     MacroAssembler masm(cx);
+    // Caller:
+    // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp
+    // '--- #r8 ---'
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     MOZ_ASSERT(ArgumentsRectifierReg == r8);
 
-    // Load the number of |undefined|s to push into %rcx.
+    // Add |this|, in the counter of known arguments.
+    masm.addl(Imm32(1), r8);
+
+    // Load |nformals| into %rcx.
     masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfCalleeToken()), rax);
     masm.mov(rax, rcx);
     masm.andq(Imm32(uint32_t(CalleeTokenMask)), rcx);
     masm.movzwl(Operand(rcx, JSFunction::offsetOfNargs()), rcx);
+
+    // Including |this|, there are (|nformals| + 1) arguments to push to the
+    // stack.  Then we push a JitFrameLayout.  We compute the padding expressed
+    // in the number of extra |undefined| values to push on the stack.
+    static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
+      "No need to consider the JitFrameLayout for aligning the stack");
+    static_assert(JitStackAlignment % sizeof(Value) == 0,
+      "Ensure that we can pad the stack by pushing extra UndefinedValue");
+
+    const uint32_t alignment = JitStackAlignment / sizeof(Value);
+    MOZ_ASSERT(IsPowerOfTwo(alignment));
+    masm.addl(Imm32(alignment - 1 /* for padding */ + 1 /* for |this| */), rcx);
+    masm.andl(Imm32(~(alignment - 1)), rcx);
+
+    // Load the number of |undefined|s to push into %rcx.
     masm.subq(r8, rcx);
 
+    // Caller:
+    // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- rsp <- r9
+    // '------ #r8 -------'
+    //
+    // Rectifier frame:
+    // [undef] [undef] [undef] [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]]
+    // '------- #rcx --------' '------ #r8 -------'
+
     // Copy the number of actual arguments
     masm.loadPtr(Address(rsp, RectifierFrameLayout::offsetOfNumActualArgs()), rdx);
 
     masm.moveValue(UndefinedValue(), r10);
 
     masm.movq(rsp, r9); // Save %rsp.
 
-    // Push undefined.
+    // Push undefined. (including the padding)
     {
         Label undefLoopTop;
         masm.bind(&undefLoopTop);
 
         masm.push(r10);
         masm.subl(Imm32(1), rcx);
         masm.j(Assembler::NonZero, &undefLoopTop);
     }
 
     // Get the topmost argument.
-    BaseIndex b = BaseIndex(r9, r8, TimesEight, sizeof(RectifierFrameLayout));
+    static_assert(sizeof(Value) == 8, "TimesEight is used to skip arguments");
+
+    // | - sizeof(Value)| is used to put rcx such that we can read the last
+    // argument, and not the value which is after.
+    BaseIndex b = BaseIndex(r9, r8, TimesEight, sizeof(RectifierFrameLayout) - sizeof(Value));
     masm.lea(Operand(b), rcx);
 
-    // Push arguments, |nargs| + 1 times (to include |this|).
-    masm.addl(Imm32(1), r8);
+    // Copy & Push arguments, |nargs| + 1 times (to include |this|).
     {
         Label copyLoopTop;
 
         masm.bind(&copyLoopTop);
         masm.push(Operand(rcx, 0x0));
         masm.subq(Imm32(sizeof(Value)), rcx);
         masm.subl(Imm32(1), r8);
         masm.j(Assembler::NonZero, &copyLoopTop);
     }
 
+    // Caller:
+    // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- r9
+    //
+    //
+    // Rectifier frame:
+    // [undef] [undef] [undef] [arg2] [arg1] [this] <- rsp [[argc] [callee] [descr] [raddr]]
+    //
+
     // Construct descriptor.
     masm.subq(rsp, r9);
     masm.makeFrameDescriptor(r9, JitFrame_Rectifier);
 
     // Construct JitFrameLayout.
     masm.push(rdx); // numActualArgs
     masm.push(rax); // callee token
     masm.push(r9); // descriptor
--- a/js/src/jit/x86/Trampoline-x86.cpp
+++ b/js/src/jit/x86/Trampoline-x86.cpp
@@ -365,39 +365,69 @@ JitRuntime::generateInvalidator(JSContex
 
     return code;
 }
 
 JitCode *
 JitRuntime::generateArgumentsRectifier(JSContext *cx, void **returnAddrOut)
 {
     MacroAssembler masm(cx);
+    // Caller:
+    // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]] <- esp
+    // '-- #esi ---'
 
     // ArgumentsRectifierReg contains the |nargs| pushed onto the current frame.
     // Including |this|, there are (|nargs| + 1) arguments to copy.
     MOZ_ASSERT(ArgumentsRectifierReg == esi);
 
     // Load the number of |undefined|s to push into %ecx.
     masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfCalleeToken()), eax);
     masm.mov(eax, ecx);
     masm.andl(Imm32(CalleeTokenMask), ecx);
     masm.movzwl(Operand(ecx, JSFunction::offsetOfNargs()), ecx);
+
+    // The frame pointer and its padding are pushed on the stack.
+    // Including |this|, there are (|nformals| + 1) arguments to push to the
+    // stack.  Then we push a JitFrameLayout.  We compute the padding expressed
+    // in the number of extra |undefined| values to push on the stack.
+    static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
+      "No need to consider the JitFrameLayout for aligning the stack");
+    static_assert((sizeof(Value) + 2 * sizeof(void *)) % JitStackAlignment == 0,
+      "No need to consider |this| and the frame pointer and its padding for aligning the stack");
+    static_assert(JitStackAlignment % sizeof(Value) == 0,
+      "Ensure that we can pad the stack by pushing extra UndefinedValue");
+
+    const uint32_t alignment = JitStackAlignment / sizeof(Value);
+    MOZ_ASSERT(IsPowerOfTwo(alignment));
+    masm.addl(Imm32(alignment - 1 /* for padding */), ecx);
+    masm.andl(Imm32(~(alignment - 1)), ecx);
     masm.subl(esi, ecx);
 
     // Copy the number of actual arguments.
     masm.loadPtr(Address(esp, RectifierFrameLayout::offsetOfNumActualArgs()), edx);
 
     masm.moveValue(UndefinedValue(), ebx, edi);
 
     // NOTE: The fact that x86 ArgumentsRectifier saves the FramePointer is relied upon
     // by the baseline bailout code.  If this changes, fix that code!  See
     // BaselineJIT.cpp/BaselineStackBuilder::calculatePrevFramePtr, and
     // BaselineJIT.cpp/InitFromBailout.  Check for the |#if defined(JS_CODEGEN_X86)| portions.
     masm.push(FramePointer);
     masm.movl(esp, FramePointer); // Save %esp.
+    masm.push(FramePointer /* padding */);
+
+    // Caller:
+    // [arg2] [arg1] [this] [[argc] [callee] [descr] [raddr]]
+    // '-- #esi ---'
+    //
+    // Rectifier frame:
+    // [ebp'] <- ebp [padding] <- esp [undef] [undef] [arg2] [arg1] [this]
+    //                                '--- #ecx ----' '-- #esi ---'
+    //
+    // [[argc] [callee] [descr] [raddr]]
 
     // Push undefined.
     {
         Label undefLoopTop;
         masm.bind(&undefLoopTop);
 
         masm.push(ebx); // type(undefined);
         masm.push(edi); // payload(undefined);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1727,17 +1727,17 @@ JS_SetNativeStackQuota(JSRuntime *rt, si
         untrustedScriptStackSize = trustedScriptStackSize;
     else
         MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize);
 
     SetNativeStackQuotaAndLimit(rt, StackForSystemCode, systemCodeStackSize);
     SetNativeStackQuotaAndLimit(rt, StackForTrustedScript, trustedScriptStackSize);
     SetNativeStackQuotaAndLimit(rt, StackForUntrustedScript, untrustedScriptStackSize);
 
-    rt->mainThread.initJitStackLimit();
+    rt->initJitStackLimit();
 }
 
 /************************************************************************/
 
 JS_PUBLIC_API(int)
 JS_IdArrayLength(JSContext *cx, JSIdArray *ida)
 {
     return ida->length;
@@ -5889,26 +5889,26 @@ GetScriptedCallerGlobal(JSContext *cx)
 
 JS_PUBLIC_API(void)
 HideScriptedCaller(JSContext *cx)
 {
     MOZ_ASSERT(cx);
 
     // If there's no accessible activation on the stack, we'll return null from
     // DescribeScriptedCaller anyway, so there's no need to annotate anything.
-    Activation *act = cx->runtime()->mainThread.activation();
+    Activation *act = cx->runtime()->activation();
     if (!act)
         return;
     act->hideScriptedCaller();
 }
 
 JS_PUBLIC_API(void)
 UnhideScriptedCaller(JSContext *cx)
 {
-    Activation *act = cx->runtime()->mainThread.activation();
+    Activation *act = cx->runtime()->activation();
     if (!act)
         return;
     act->unhideScriptedCaller();
 }
 
 } /* namespace JS */
 
 static PRStatus
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1042,17 +1042,17 @@ JSContext::isThrowingOutOfMemory()
 }
 
 bool
 JSContext::saveFrameChain()
 {
     if (!savedFrameChains_.append(SavedFrameChain(compartment(), enterCompartmentDepth_)))
         return false;
 
-    if (Activation *act = mainThread().activation())
+    if (Activation *act = runtime()->activation())
         act->saveFrameChain();
 
     setCompartment(nullptr);
     enterCompartmentDepth_ = 0;
 
     return true;
 }
 
@@ -1060,17 +1060,17 @@ void
 JSContext::restoreFrameChain()
 {
     MOZ_ASSERT(enterCompartmentDepth_ == 0); // We're about to clobber it, and it
                                             // will be wrong forevermore.
     SavedFrameChain sfc = savedFrameChains_.popCopy();
     setCompartment(sfc.compartment);
     enterCompartmentDepth_ = sfc.enterCompartmentCount;
 
-    if (Activation *act = mainThread().activation())
+    if (Activation *act = runtime()->activation())
         act->restoreFrameChain();
 }
 
 bool
 JSContext::currentlyRunning() const
 {
     for (ActivationIterator iter(runtime()); !iter.done(); ++iter) {
         if (iter->cx() == this) {
@@ -1185,17 +1185,17 @@ JSContext::mark(JSTracer *trc)
     if (compartment_)
         compartment_->mark();
 }
 
 void *
 ExclusiveContext::stackLimitAddressForJitCode(StackKind kind)
 {
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-    return runtime_->mainThread.addressOfSimulatorStackLimit();
+    return runtime_->addressOfSimulatorStackLimit();
 #endif
     return stackLimitAddress(kind);
 }
 
 JSVersion
 JSContext::findVersion() const
 {
     if (JSScript *script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT))
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -236,16 +236,17 @@ class ExclusiveContext : public ContextF
     WellKnownSymbols &wellKnownSymbols() { return *runtime_->wellKnownSymbols; }
     const JS::AsmJSCacheOps &asmJSCacheOps() { return runtime_->asmJSCacheOps; }
     PropertyName *emptyString() { return runtime_->emptyString; }
     FreeOp *defaultFreeOp() { return runtime_->defaultFreeOp(); }
     void *runtimeAddressForJit() { return runtime_; }
     void *runtimeAddressOfInterruptUint32() { return runtime_->addressOfInterruptUint32(); }
     void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; }
     void *stackLimitAddressForJitCode(StackKind kind);
+    uintptr_t stackLimit(StackKind kind) { return runtime_->mainThread.nativeStackLimit[kind]; }
     size_t gcSystemPageSize() { return gc::SystemPageSize(); }
     bool canUseSignalHandlers() const { return runtime_->canUseSignalHandlers(); }
     bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; }
     bool jitSupportsSimd() const { return runtime_->jitSupportsSimd; }
 
     // Thread local data that may be accessed freely.
     DtoaState *dtoaState() {
         return perThreadData->dtoaState;
@@ -430,26 +431,26 @@ struct JSContext : public js::ExclusiveC
     bool jitIsBroken;
 
     void updateJITEnabled();
 
     /* Whether this context has JS frames on the stack. */
     bool currentlyRunning() const;
 
     bool currentlyRunningInInterpreter() const {
-        return mainThread().activation()->isInterpreter();
+        return runtime_->activation()->isInterpreter();
     }
     bool currentlyRunningInJit() const {
-        return mainThread().activation()->isJit();
+        return runtime_->activation()->isJit();
     }
     js::InterpreterFrame *interpreterFrame() const {
-        return mainThread().activation()->asInterpreter()->current();
+        return runtime_->activation()->asInterpreter()->current();
     }
     js::InterpreterRegs &interpreterRegs() const {
-        return mainThread().activation()->asInterpreter()->regs();
+        return runtime_->activation()->asInterpreter()->regs();
     }
 
     /*
      * Get the topmost script and optional pc on the stack. By default, this
      * function only returns a JSScript in the current compartment, returning
      * nullptr if the current script is in a different compartment. This
      * behavior can be overridden by passing ALLOW_CROSS_COMPARTMENT.
      */
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -443,17 +443,17 @@ js::ExclusiveContext::setCompartment(JSC
 
 inline JSScript *
 JSContext::currentScript(jsbytecode **ppc,
                          MaybeAllowCrossCompartment allowCrossCompartment) const
 {
     if (ppc)
         *ppc = nullptr;
 
-    js::Activation *act = mainThread().activation();
+    js::Activation *act = runtime()->activation();
     while (act && (act->cx() != this || (act->isJit() && !act->asJit()->isActive())))
         act = act->prev();
 
     if (!act)
         return nullptr;
 
     MOZ_ASSERT(act->cx() == this);
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2280,16 +2280,17 @@ TypeObject *
 TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key)
 {
     AutoEnterAnalysis enter(cx);
 
     if (!allocationSiteTable) {
         allocationSiteTable = cx->new_<AllocationSiteTable>();
         if (!allocationSiteTable || !allocationSiteTable->init()) {
             js_delete(allocationSiteTable);
+            allocationSiteTable = nullptr;
             return nullptr;
         }
     }
 
     AllocationSiteTable::AddPtr p = allocationSiteTable->lookupForAdd(key);
     MOZ_ASSERT(!p);
 
     TypeObject *res = nullptr;
@@ -3325,17 +3326,18 @@ TypeObject::clearNewScript(ExclusiveCont
         if (prop->types.definiteProperty())
             prop->types.setNonDataProperty(cx);
     }
 
     if (cx->isJSContext()) {
         newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
     } else {
         // Threads with an ExclusiveContext are not allowed to run scripts.
-        MOZ_ASSERT(!cx->perThreadData->activation());
+        MOZ_ASSERT(!cx->perThreadData->runtimeIfOnOwnerThread() ||
+                   !cx->perThreadData->runtimeIfOnOwnerThread()->activation());
     }
 
     js_delete(newScript);
     markStateChange(cx);
 }
 
 void
 TypeObject::print()
@@ -4606,39 +4608,53 @@ ConstraintTypeSet::sweep(Zone *zone, Aut
     if (objectCount >= 2) {
         unsigned oldCapacity = HashSetCapacity(objectCount);
         TypeObjectKey **oldArray = objectSet;
 
         clearObjects();
         objectCount = 0;
         for (unsigned i = 0; i < oldCapacity; i++) {
             TypeObjectKey *object = oldArray[i];
-            if (object && !IsAboutToBeFinalized(&object)) {
+            if (!object)
+                continue;
+            if (!IsAboutToBeFinalized(&object)) {
                 TypeObjectKey **pentry =
                     HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
                         (zone->types.typeLifoAlloc, objectSet, objectCount, object);
                 if (pentry) {
                     *pentry = object;
                 } else {
                     oom.setOOM();
                     flags |= TYPE_FLAG_ANYOBJECT;
                     clearObjects();
                     objectCount = 0;
                     break;
                 }
+            } else if (object->isTypeObject() && object->asTypeObject()->unknownProperties()) {
+                // Object sets containing objects with unknown properties might
+                // not be complete. Mark the type set as unknown, which it will
+                // be treated as during Ion compilation.
+                flags |= TYPE_FLAG_ANYOBJECT;
+                clearObjects();
+                objectCount = 0;
+                break;
             }
         }
         setBaseObjectCount(objectCount);
     } else if (objectCount == 1) {
         TypeObjectKey *object = (TypeObjectKey *) objectSet;
-        if (IsAboutToBeFinalized(&object)) {
+        if (!IsAboutToBeFinalized(&object)) {
+            objectSet = reinterpret_cast<TypeObjectKey **>(object);
+        } else {
+            // As above, mark type sets containing objects with unknown
+            // properties as unknown.
+            if (object->isTypeObject() && object->asTypeObject()->unknownProperties())
+                flags |= TYPE_FLAG_ANYOBJECT;
             objectSet = nullptr;
             setBaseObjectCount(0);
-        } else {
-            objectSet = reinterpret_cast<TypeObjectKey **>(object);
         }
     }
 
     /*
      * Type constraints only hold weak references. Copy constraints referring
      * to data that is still live into the zone's new arena.
      */
     TypeConstraint *constraint = constraintList;
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -449,17 +449,17 @@ struct PerThreadDataFriendFields
   public:
     template <class T>
     inline JS::Rooted<T> *gcRooters() {
         js::ThingRootKind kind = RootKind<T>::rootKind();
         return reinterpret_cast<JS::Rooted<T> *>(thingGCRooters[kind]);
     }
 
     /* Limit pointer for checking native stack consumption. */
-    uintptr_t nativeStackLimit[StackKindCount];
+    uintptr_t nativeStackLimit[js::StackKindCount];
 
     static const size_t RuntimeMainThreadOffset = offsetof(RuntimeDummy, mainThread);
 
     static inline PerThreadDataFriendFields *get(js::PerThreadData *pt) {
         return reinterpret_cast<PerThreadDataFriendFields *>(pt);
     }
 
     static inline PerThreadDataFriendFields *getMainThread(JSRuntime *rt) {
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4204,34 +4204,34 @@ SingleStepCallback(void *arg, jit::Simul
 #endif
 
 static bool
 EnableSingleStepProfiling(JSContext *cx, unsigned argc, Value *vp)
 {
 #if defined(JS_ARM_SIMULATOR)
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    jit::Simulator *sim = cx->runtime()->mainThread.simulator();
+    jit::Simulator *sim = cx->runtime()->simulator();
     sim->enable_single_stepping(SingleStepCallback, cx->runtime());
 
     args.rval().setUndefined();
     return true;
 #else
     JS_ReportError(cx, "single-step profiling not enabled on this platform");
     return false;
 #endif
 }
 
 static bool
 DisableSingleStepProfiling(JSContext *cx, unsigned argc, Value *vp)
 {
 #if defined(JS_ARM_SIMULATOR)
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    jit::Simulator *sim = cx->runtime()->mainThread.simulator();
+    jit::Simulator *sim = cx->runtime()->simulator();
     sim->disable_single_stepping();
 
     AutoValueVector elems(cx);
     for (size_t i = 0; i < stacks.length(); i++) {
         JSString *stack = JS_NewUCStringCopyN(cx, stacks[i].begin(), stacks[i].length());
         if (!stack)
             return false;
         if (!elems.append(StringValue(stack)))
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1079,69 +1079,86 @@ Debugger::receiveCompletionValue(Maybe<A
 
     JSTrapStatus status;
     RootedValue value(cx);
     resultToCompletion(cx, ok, val, &status, &value);
     ac.reset();
     return newCompletionValue(cx, status, value, vp);
 }
 
+static bool
+GetStatusProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, JSTrapStatus status,
+                  JSTrapStatus *statusOut, MutableHandleValue vp, int *hits)
+{
+    bool found;
+    if (!HasProperty(cx, obj, name, &found))
+        return false;
+    if (found) {
+        ++*hits;
+        *statusOut = status;
+        if (!GetProperty(cx, obj, obj, name, vp))
+            return false;
+    }
+    return true;
+}
+
+static bool
+ParseResumptionValueAsObject(JSContext *cx, HandleValue rv, JSTrapStatus *statusp,
+                             MutableHandleValue vp)
+{
+    int hits = 0;
+    if (rv.isObject()) {
+        RootedObject obj(cx, &rv.toObject());
+        if (!GetStatusProperty(cx, obj, cx->names().return_, JSTRAP_RETURN, statusp, vp, &hits))
+            return false;
+        if (!GetStatusProperty(cx, obj, cx->names().throw_, JSTRAP_THROW, statusp, vp, &hits))
+            return false;
+    }
+
+    if (hits != 1) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_RESUMPTION);
+        return false;
+    }
+    return true;
+}
+
 JSTrapStatus
 Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value &rv, MutableHandleValue vp,
                                bool callHook)
 {
     vp.setUndefined();
     if (!ok)
         return handleUncaughtException(ac, vp, callHook);
     if (rv.isUndefined()) {
         ac.reset();
         return JSTRAP_CONTINUE;
     }
     if (rv.isNull()) {
         ac.reset();
         return JSTRAP_ERROR;
     }
 
-    /* Check that rv is {return: val} or {throw: val}. */
     JSContext *cx = ac->context()->asJSContext();
-    Rooted<JSObject*> obj(cx);
-    RootedShape shape(cx);
-    RootedId returnId(cx, NameToId(cx->names().return_));
-    RootedId throwId(cx, NameToId(cx->names().throw_));
-    bool okResumption = rv.isObject();
-    if (okResumption) {
-        obj = &rv.toObject();
-        okResumption = obj->is<PlainObject>();
-    }
-    if (okResumption) {
-        shape = obj->lastProperty();
-        okResumption = shape->previous() &&
-             !shape->previous()->previous() &&
-             (shape->propid() == returnId || shape->propid() == throwId) &&
-             shape->isDataDescriptor();
-    }
-    if (!okResumption) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_BAD_RESUMPTION);
+    JSTrapStatus status = JSTRAP_CONTINUE;
+    RootedValue v(cx);
+    RootedValue rvRoot(cx, rv);
+    if (!ParseResumptionValueAsObject(cx, rvRoot, &status, &v) ||
+        !unwrapDebuggeeValue(cx, &v))
+    {
         return handleUncaughtException(ac, vp, callHook);
     }
 
-    HandleNativeObject nobj = obj.as<NativeObject>();
-
-    RootedValue v(cx, vp.get());
-    if (!NativeGetExistingProperty(cx, obj, nobj, shape, &v) || !unwrapDebuggeeValue(cx, &v))
-        return handleUncaughtException(ac, &v, callHook);
-
     ac.reset();
     if (!cx->compartment()->wrap(cx, &v)) {
         vp.setUndefined();
         return JSTRAP_ERROR;
     }
     vp.set(v);
 
-    return shape->propid() == returnId ? JSTRAP_RETURN : JSTRAP_THROW;
+    return status;
 }
 
 static bool
 CallMethodIfPresent(JSContext *cx, HandleObject obj, const char *name, int argc, Value *argv,
                     MutableHandleValue rval)
 {
     rval.setUndefined();
     JSAtom *atom = Atomize(cx, name, strlen(name));
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -1513,32 +1513,48 @@ js::NativeDefineElement(ExclusiveContext
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
 
     if (!IndexToId(cx, index, &id))
         return false;
 
     return NativeDefineProperty(cx, obj, id, value, getter, setter, attrs);
 }
 
+
+/*** [[Get]] *************************************************************************************/
+
+static inline bool
+CallGetter(JSContext* cx, HandleObject receiver, HandleShape shape, MutableHandleValue vp)
+{
+    MOZ_ASSERT(!shape->hasDefaultGetter());
+
+    if (shape->hasGetterValue()) {
+        Value fval = shape->getterValue();
+        return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
+    }
+
+    RootedId id(cx, shape->propid());
+    return CallJSPropertyOp(cx, shape->getterOp(), receiver, id, vp);
+}
+
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
-NativeGetExistingPropertyInline(JSContext *cx,
-                                typename MaybeRooted<JSObject*, allowGC>::HandleType obj,
-                                typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
-                                typename MaybeRooted<NativeObject*, allowGC>::HandleType pobj,
-                                typename MaybeRooted<Shape*, allowGC>::HandleType shape,
-                                typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
+GetExistingProperty(JSContext *cx,
+                    typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
+                    typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
+                    typename MaybeRooted<Shape*, allowGC>::HandleType shape,
+                    typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
     if (shape->hasSlot()) {
-        vp.set(pobj->getSlot(shape->slot()));
+        vp.set(obj->getSlot(shape->slot()));
         MOZ_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) &&
-                      !pobj->hasSingletonType() &&
-                      !pobj->template is<ScopeObject>() &&
+                      !obj->hasSingletonType() &&
+                      !obj->template is<ScopeObject>() &&
                       shape->hasDefaultGetter(),
-                      js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp));
+                      js::types::TypeHasProperty(cx, obj->type(), shape->propid(), vp));
     } else {
         vp.setUndefined();
     }
     if (shape->hasDefaultGetter())
         return true;
 
     {
         jsbytecode *pc;
@@ -1554,228 +1570,258 @@ NativeGetExistingPropertyInline(JSContex
                 break;
             }
         }
     }
 
     if (!allowGC)
         return false;
 
-    if (!shape->get(cx,
+    if (!CallGetter(cx,
                     MaybeRooted<JSObject*, allowGC>::toHandle(receiver),
-                    MaybeRooted<JSObject*, allowGC>::toHandle(obj),
-                    MaybeRooted<JSObject*, allowGC>::toHandle(pobj),
+                    MaybeRooted<Shape*, allowGC>::toHandle(shape),
                     MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
     {
         return false;
     }
 
-    /* Update slotful shapes according to the value produced by the getter. */
-    if (shape->hasSlot() && pobj->contains(cx, shape))
-        pobj->setSlot(shape->slot(), vp);
+    // Ancient nonstandard extension: via the JSAPI it's possible to create a
+    // data property that has both a slot and a getter. In that case, copy the
+    // value returned by the getter back into the slot.
+    if (shape->hasSlot() && obj->contains(cx, shape))
+        obj->setSlot(shape->slot(), vp);
 
     return true;
 }
 
 bool
-js::NativeGetExistingProperty(JSContext *cx, HandleObject obj, HandleNativeObject pobj,
+js::NativeGetExistingProperty(JSContext *cx, HandleObject receiver, HandleNativeObject obj,
                               HandleShape shape, MutableHandleValue vp)
 {
-    return NativeGetExistingPropertyInline<CanGC>(cx, obj, obj, pobj, shape, vp);
+    return GetExistingProperty<CanGC>(cx, receiver, obj, shape, vp);
 }
 
 /*
  * Given pc pointing after a property accessing bytecode, return true if the
- * access is "object-detecting" in the sense used by web scripts, e.g., when
- * checking whether document.all is defined.
+ * access is "property-detecting" -- that is, if we shouldn't warn about it
+ * even if no such property is found and strict warnings are enabled.
  */
 static bool
 Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     MOZ_ASSERT(script->containsPC(pc));
 
-    /* General case: a branch or equality op follows the access. */
+    // General case: a branch or equality op follows the access.
     JSOp op = JSOp(*pc);
     if (js_CodeSpec[op].format & JOF_DETECTING)
         return true;
 
     jsbytecode *endpc = script->codeEnd();
 
     if (op == JSOP_NULL) {
-        /*
-         * Special case #1: handle (document.all == null).  Don't sweat
-         * about JS1.2's revision of the equality operators here.
-         */
+        // Special case #1: don't warn about (obj.prop == null).
         if (++pc < endpc) {
             op = JSOp(*pc);
             return op == JSOP_EQ || op == JSOP_NE;
         }
         return false;
     }
 
     if (op == JSOP_GETGNAME || op == JSOP_GETNAME) {
-        /*
-         * Special case #2: handle (document.all == undefined).  Don't worry
-         * about a local variable named |undefined| shadowing the immutable
-         * global binding...because, really?
-         */
+        // Special case #2: don't warn about (obj.prop == undefined).
         JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc));
         if (atom == cx->names().undefined &&
             (pc += js_CodeSpec[op].length) < endpc) {
             op = JSOp(*pc);
             return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
         }
     }
 
     return false;
 }
 
+/*
+ * Finish getting the property `receiver[id]` after looking at every object on
+ * the prototype chain and not finding any such property.
+ *
+ * Per the spec, this should just set the result to `undefined` and call it a
+ * day. However:
+ *
+ * 1.  We add support for the nonstandard JSClass::getProperty hook.
+ *
+ * 2.  This function also runs when we're evaluating an expression that's an
+ *     Identifier (that is, an unqualified name lookup), so we need to figure
+ *     out if that's what's happening and throw a ReferenceError if so.
+ *
+ * 3.  We also emit an optional warning for this. (It's not super useful on the
+ *     web, as there are too many false positives, but anecdotally useful in
+ *     Gecko code.)
+ */
+static bool
+GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
+                       HandleObject receiver, MutableHandleValue vp)
+{
+    vp.setUndefined();
+
+    // Non-standard extension: Call the getProperty hook. If it sets vp to a
+    // value other than undefined, we're done. If not, fall through to the
+    // warning/error checks below.
+    if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
+        if (!CallJSPropertyOp(cx, getProperty, obj, id, vp))
+            return false;
+
+        if (!vp.isUndefined())
+            return true;
+    }
+
+    // If we are doing a name lookup, this is a ReferenceError.
+    jsbytecode *pc = nullptr;
+    RootedScript script(cx, cx->currentScript(&pc));
+    if (!pc)
+        return true;
+    JSOp op = (JSOp) *pc;
+    if (op == JSOP_GETXPROP) {
+        JSAutoByteString printable;
+        if (js_ValueToPrintable(cx, IdToValue(id), &printable))
+            js_ReportIsNotDefined(cx, printable.ptr());
+        return false;
+    }
+
+    // Give a strict warning if foo.bar is evaluated by a script for an object
+    // foo with no property named 'bar'.
+    //
+    // Don't warn if extra warnings not enabled or for random getprop
+    // operations.
+    if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
+        return true;
+
+    // Don't warn repeatedly for the same script.
+    if (!script || script->warnedAboutUndefinedProp())
+        return true;
+
+    // Don't warn in self-hosted code (where the further presence of
+    // JS::RuntimeOptions::werror() would result in impossible-to-avoid
+    // errors to entirely-innocent client code).
+    if (script->selfHosted())
+        return true;
+
+    // We may just be checking if that object has an iterator.
+    if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
+        return true;
+
+    // Do not warn about tests like (obj[prop] == undefined).
+    pc += js_CodeSpec[op].length;
+    if (Detecting(cx, script, pc))
+        return true;
+
+    unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
+    script->setWarnedAboutUndefinedProp();
+
+    // Ok, bad undefined property reference: whine about it.
+    RootedValue val(cx, IdToValue(id));
+    return js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, JSDVG_IGNORE_STACK, val,
+                                    js::NullPtr(), nullptr, nullptr);
+}
+
+/* The NoGC version of GetNonexistentProperty, present only to make types line up. */
+bool
+GetNonexistentProperty(JSContext *cx, NativeObject *obj, jsid id, JSObject *receiver,
+                       FakeMutableHandle<Value> vp)
+{
+    return false;
+}
+
+static inline bool
+GeneralizedGetProperty(JSContext *cx, HandleObject obj, HandleId id, HandleObject receiver,
+                       MutableHandleValue vp)
+{
+    JS_CHECK_RECURSION(cx, return false);
+    return GetProperty(cx, obj, receiver, id, vp);
+}
+
+static inline bool
+GeneralizedGetProperty(JSContext *cx, JSObject *obj, jsid id, JSObject *receiver,
+                       FakeMutableHandle<Value> vp)
+{
+    JS_CHECK_RECURSION_DONT_REPORT(cx, return false);
+    return GetPropertyNoGC(cx, obj, receiver, id, vp.address());
+}
+
 template <AllowGC allowGC>
 static MOZ_ALWAYS_INLINE bool
-GetPropertyHelperInline(JSContext *cx,
+NativeGetPropertyInline(JSContext *cx,
                         typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
                         typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
                         typename MaybeRooted<jsid, allowGC>::HandleType id,
                         typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
 {
-    /* This call site is hot -- use the always-inlined variant of LookupNativeProperty(). */
-    typename MaybeRooted<JSObject*, allowGC>::RootType obj2(cx);
+    typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
     typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
-    if (!LookupPropertyInline<allowGC>(cx, obj, id, &obj2, &shape))
-        return false;
 
-    if (!shape) {
-        if (!allowGC)
+    // This loop isn't explicit in the spec algorithm. See the comment on step
+    // 4.d below.
+    for (;;) {
+        // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
+        bool done;
+        if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done))
             return false;
 
-        vp.setUndefined();
-
-        if (JSPropertyOp getProperty = obj->getClass()->getProperty) {
-            if (!CallJSPropertyOp(cx, getProperty,
-                                  MaybeRooted<JSObject*, allowGC>::toHandle(obj),
-                                  MaybeRooted<jsid, allowGC>::toHandle(id),
-                                  MaybeRooted<Value, allowGC>::toMutableHandle(vp)))
-            {
-                return false;
+        if (shape) {
+            // Steps 5-8. Special case for dense elements because
+            // GetExistingProperty doesn't support those.
+            if (IsImplicitDenseOrTypedArrayElement(shape)) {
+                vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
+                return true;
             }
+            return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp);
         }
 
-        /*
-         * Give a strict warning if foo.bar is evaluated by a script for an
-         * object foo with no property named 'bar'.
-         */
-        if (vp.isUndefined()) {
-            jsbytecode *pc = nullptr;
-            RootedScript script(cx, cx->currentScript(&pc));
-            if (!pc)
-                return true;
-            JSOp op = (JSOp) *pc;
-
-            if (op == JSOP_GETXPROP) {
-                /* Undefined property during a name lookup, report an error. */
-                JSAutoByteString printable;
-                if (js_ValueToPrintable(cx, IdToValue(id), &printable))
-                    js_ReportIsNotDefined(cx, printable.ptr());
-                return false;
-            }
-
-            /* Don't warn if extra warnings not enabled or for random getprop operations. */
-            if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
-                return true;
-
-            /* Don't warn repeatedly for the same script. */
-            if (!script || script->warnedAboutUndefinedProp())
-                return true;
-
-            /*
-             * Don't warn in self-hosted code (where the further presence of
-             * JS::RuntimeOptions::werror() would result in impossible-to-avoid
-             * errors to entirely-innocent client code).
-             */
-            if (script->selfHosted())
-                return true;
-
-            /* We may just be checking if that object has an iterator. */
-            if (JSID_IS_ATOM(id, cx->names().iteratorIntrinsic))
-                return true;
+        // Steps 4.a-b. The check for 'done' on this next line is tricky.
+        // done can be true in exactly these unlikely-sounding cases:
+        // - We're looking up an element, and pobj is a TypedArray that
+        //   doesn't have that many elements.
+        // - We're being called from a resolve hook to assign to the property
+        //   being resolved.
+        // What they all have in common is we do not want to keep walking
+        // the prototype chain.
+        RootedObject proto(cx, done ? nullptr : pobj->getProto());
 
-            /* Do not warn about tests like (obj[prop] == undefined). */
-            pc += js_CodeSpec[op].length;
-            if (Detecting(cx, script, pc))
-                return true;
-
-            unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
-            script->setWarnedAboutUndefinedProp();
-
-            /* Ok, bad undefined property reference: whine about it. */
-            RootedValue val(cx, IdToValue(id));
-            if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP,
-                                          JSDVG_IGNORE_STACK, val, js::NullPtr(),
-                                          nullptr, nullptr))
-            {
-                return false;
-            }
-        }
-        return true;
-    }
+        // Step 4.c. The spec algorithm simply returns undefined if proto is
+        // null, but see the comment on GetNonexistentProperty.
+        if (!proto)
+            return GetNonexistentProperty(cx, obj, id, receiver, vp);
 
-    if (!obj2->isNative()) {
-        if (!allowGC)
-            return false;
-        HandleObject obj2Handle = MaybeRooted<JSObject*, allowGC>::toHandle(obj2);
-        HandleObject receiverHandle = MaybeRooted<JSObject*, allowGC>::toHandle(receiver);
-        HandleId idHandle = MaybeRooted<jsid, allowGC>::toHandle(id);
-        MutableHandleValue vpHandle = MaybeRooted<Value, allowGC>::toMutableHandle(vp);
-        return obj2->template is<ProxyObject>()
-               ? Proxy::get(cx, obj2Handle, receiverHandle, idHandle, vpHandle)
-               : GetProperty(cx, obj2Handle, obj2Handle, idHandle, vpHandle);
-    }
+        // Step 4.d. If the prototype is also native, this step is a
+        // recursive tail call, and we don't need to go through all the
+        // plumbing of JSObject::getGeneric; the top of the loop is where
+        // we're going to end up anyway. But if pobj is non-native,
+        // that optimization would be incorrect.
+        if (!proto->isNative())
+            return GeneralizedGetProperty(cx, proto, id, receiver, vp);
 
-    typename MaybeRooted<NativeObject*, allowGC>::HandleType nobj2 =
-        MaybeRooted<JSObject*, allowGC>::template downcastHandle<NativeObject>(obj2);
-
-    if (IsImplicitDenseOrTypedArrayElement(shape)) {
-        vp.set(nobj2->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
-        return true;
+        pobj = &proto->as<NativeObject>();
     }
-
-    // This call site is hot -- use the always-inlined variant of
-    // NativeGetExistingProperty().
-    if (!NativeGetExistingPropertyInline<allowGC>(cx, obj, receiver, nobj2, shape, vp))
-        return false;
-
-    return true;
 }
 
 bool
 js::NativeGetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
                       MutableHandleValue vp)
 {
-    /* This call site is hot -- use the always-inlined variant of GetPropertyHelper(). */
-    return GetPropertyHelperInline<CanGC>(cx, obj, receiver, id, vp);
+    return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, vp);
 }
 
 bool
 js::NativeGetPropertyNoGC(JSContext *cx, NativeObject *obj, JSObject *receiver, jsid id, Value *vp)
 {
-    AutoAssertNoException nogc(cx);
-    return GetPropertyHelperInline<NoGC>(cx, obj, receiver, id, vp);
+    AutoAssertNoException noexc(cx);
+    return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, vp);
 }
 
-bool
-js::NativeGetElement(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
-                     MutableHandleValue vp)
-{
-    RootedId id(cx);
-    if (!IndexToId(cx, index, &id))
-        return false;
 
-    /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
-    return GetPropertyHelperInline<CanGC>(cx, obj, receiver, id, vp);
-}
+/*** [[Set]] *************************************************************************************/
 
 static bool
 MaybeReportUndeclaredVarAssignment(JSContext *cx, JSString *propname)
 {
     {
         jsbytecode *pc;
         JSScript *script = cx->currentScript(&pc, JSContext::ALLOW_CROSS_COMPARTMENT);
         if (!script)
@@ -1791,19 +1837,16 @@ MaybeReportUndeclaredVarAssignment(JSCon
     return !!bytes &&
            JS_ReportErrorFlagsAndNumber(cx,
                                         (JSREPORT_WARNING | JSREPORT_STRICT
                                          | JSREPORT_STRICT_MODE_ERROR),
                                         js_GetErrorMessage, nullptr,
                                         JSMSG_UNDECLARED_VAR, bytes.ptr());
 }
 
-
-/*** [[Set]] *************************************************************************************/
-
 /*
  * When a [[Set]] operation finds no existing property with the given id
  * or finds a writable data property on the prototype chain, we end up here.
  * Finish the [[Set]] by defining a new property on receiver.
  *
  * This implements ES6 draft rev 28, 9.1.9 [[Set]] steps 5.c-f, but it
  * is really old code and there are a few barnacles.
  */
@@ -2064,17 +2107,18 @@ js::NativeSetProperty(JSContext *cx, Han
 
     // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
     // method for ordinary objects. We substitute our own names for these names
     // used in the spec: O -> pobj, P -> id, V -> *vp, ownDesc -> shape.
     RootedShape shape(cx);
     RootedNativeObject pobj(cx, obj);
 
     // This loop isn't explicit in the spec algorithm. See the comment on step
-    // 4.c.i below.
+    // 4.c.i below. (There's a very similar loop in the NativeGetProperty
+    // implementation, but unfortunately not similar enough to common up.)
     for (;;) {
         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
         bool done;
         if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
             return false;
 
         if (shape) {
             // Steps 5-6.
@@ -2123,16 +2167,19 @@ js::NativeSetElement(JSContext *cx, Hand
                      MutableHandleValue vp, bool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict);
 }
 
+
+/* * */
+
 bool
 js::NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id,
                                 unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!NativeLookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
         return false;
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1317,18 +1317,25 @@ NativeLookupProperty(ExclusiveContext *c
 inline bool
 NativeLookupProperty(ExclusiveContext *cx, HandleNativeObject obj, PropertyName *name,
                      MutableHandleObject objp, MutableHandleShape propp);
 
 extern bool
 NativeLookupElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
                     MutableHandleObject objp, MutableHandleShape propp);
 
+/*
+ * Get a property from `receiver`, after having already done a lookup and found
+ * the property on a native object `obj`.
+ *
+ * `shape` must not be null and must not be an implicit dense property. It must
+ * be present in obj's shape chain.
+ */
 extern bool
-NativeGetExistingProperty(JSContext *cx, HandleObject obj, HandleNativeObject pobj,
+NativeGetExistingProperty(JSContext *cx, HandleObject receiver, HandleNativeObject obj,
                           HandleShape shape, MutableHandle<Value> vp);
 
 extern bool
 NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp);
 
 
 /* * */
 
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -68,75 +68,64 @@ js::DisableExtraThreads()
     gCanUseExtraThreads = false;
 }
 
 const JSSecurityCallbacks js::NullSecurityCallbacks = { };
 
 PerThreadData::PerThreadData(JSRuntime *runtime)
   : PerThreadDataFriendFields(),
     runtime_(runtime),
-    jitTop(nullptr),
-    jitJSContext(nullptr),
-    jitActivation(nullptr),
-    jitStackLimit_(0xbad),
 #ifdef JS_TRACE_LOGGING
     traceLogger(nullptr),
 #endif
-    activation_(nullptr),
-    profilingActivation_(nullptr),
-    asmJSActivationStack_(nullptr),
     autoFlushICache_(nullptr),
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-    simulator_(nullptr),
-    simulatorStackLimit_(0),
-#endif
     dtoaState(nullptr),
     suppressGC(0),
 #ifdef DEBUG
     ionCompiling(false),
 #endif
     activeCompilations(0)
 {}
 
 PerThreadData::~PerThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
-
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-    js_delete(simulator_);
-#endif
 }
 
 bool
 PerThreadData::init()
 {
     dtoaState = js_NewDtoaState();
     if (!dtoaState)
         return false;
 
-    if (!regexpStack.init())
-        return false;
-
     return true;
 }
 
 static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
     TransparentObjectWrapper,
     nullptr
 };
 
 static size_t
 ReturnZeroSize(const void *p)
 {
     return 0;
 }
 
 JSRuntime::JSRuntime(JSRuntime *parentRuntime)
   : mainThread(this),
+    jitTop(nullptr),
+    jitJSContext(nullptr),
+    jitActivation(nullptr),
+    jitStackLimit_(0xbad),
+    activation_(nullptr),
+    profilingActivation_(nullptr),
+    asmJSActivationStack_(nullptr),
     parentRuntime(parentRuntime),
     interrupt_(false),
     telemetryCallback(nullptr),
     handlingSignal(false),
     interruptCallback(nullptr),
     exclusiveAccessLock(nullptr),
     exclusiveAccessOwner(nullptr),
     mainThreadHasExclusiveAccess(false),
@@ -163,16 +152,18 @@ JSRuntime::JSRuntime(JSRuntime *parentRu
     requestDepth(0),
 #ifdef DEBUG
     checkRequestDepth(0),
     activeContext(nullptr),
 #endif
     gc(thisFromCtor()),
     gcInitialized(false),
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
+    simulator_(nullptr),
+    simulatorStackLimit_(0),
     simulatorRuntime_(nullptr),
 #endif
     scriptAndCountsVector(nullptr),
     NaNValue(DoubleNaNValue()),
     negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
     positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
     emptyString(nullptr),
 #ifdef NIGHTLY_BUILD
@@ -269,16 +260,19 @@ JSRuntime::init(uint32_t maxbytes, uint3
 
     exclusiveAccessLock = PR_NewLock();
     if (!exclusiveAccessLock)
         return false;
 
     if (!mainThread.init())
         return false;
 
+    if (!regexpStack.init())
+        return false;
+
     js::TlsPerThreadData.set(&mainThread);
 
     if (CanUseExtraThreads())
         EnsureHelperThreadsInitialized();
 
     if (!gc.init(maxbytes, maxNurseryBytes))
         return false;
 
@@ -437,16 +431,17 @@ JSRuntime::~JSRuntime()
 
     js_delete(ionPcScriptCache);
 
     gc.storeBuffer.disable();
     gc.nursery.disable();
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::DestroySimulatorRuntime(simulatorRuntime_);
+    js_delete(simulator_);
 #endif
 
     DebugOnly<size_t> oldCount = liveRuntimesCount--;
     MOZ_ASSERT(oldCount > 0);
 
     js::TlsPerThreadData.set(nullptr);
 
 #ifdef XP_WIN
@@ -589,51 +584,51 @@ InvokeInterruptCallback(JSContext *cx)
         chars = MOZ_UTF16("(stack not available)");
     JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
                                    JSMSG_TERMINATED, chars);
 
     return false;
 }
 
 void
-PerThreadData::resetJitStackLimit()
+JSRuntime::resetJitStackLimit()
 {
     // Note that, for now, we use the untrusted limit for ion. This is fine,
     // because it's the most conservative limit, and if we hit it, we'll bail
     // out of ion into the interpeter, which will do a proper recursion check.
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     jitStackLimit_ = jit::Simulator::StackLimit();
 #else
-    jitStackLimit_ = nativeStackLimit[StackForUntrustedScript];
+    jitStackLimit_ = mainThread.nativeStackLimit[StackForUntrustedScript];
 #endif
 }
 
 void
-PerThreadData::initJitStackLimit()
+JSRuntime::initJitStackLimit()
 {
     resetJitStackLimit();
 }
 
 void
 JSRuntime::requestInterrupt(InterruptMode mode)
 {
     interrupt_ = true;
-    mainThread.jitStackLimit_ = UINTPTR_MAX;
+    jitStackLimit_ = UINTPTR_MAX;
 
     if (mode == JSRuntime::RequestInterruptUrgent)
         InterruptRunningJitCode(this);
 }
 
 bool
 JSRuntime::handleInterrupt(JSContext *cx)
 {
     MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
-    if (interrupt_ || mainThread.jitStackLimit_ == UINTPTR_MAX) {
+    if (interrupt_ || jitStackLimit_ == UINTPTR_MAX) {
         interrupt_ = false;
-        mainThread.resetJitStackLimit();
+        resetJitStackLimit();
         return InvokeInterruptCallback(cx);
     }
     return true;
 }
 
 jit::ExecutableAllocator *
 JSRuntime::createExecutableAllocator(JSContext *cx)
 {
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -476,16 +476,21 @@ void DisableExtraThreads();
 /*
  * Encapsulates portions of the runtime/context that are tied to a
  * single active thread.  Instances of this structure can occur for
  * the main thread as |JSRuntime::mainThread|, for select operations
  * performed off thread, such as parsing.
  */
 class PerThreadData : public PerThreadDataFriendFields
 {
+#ifdef DEBUG
+    // Grant access to runtime_.
+    friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
+#endif
+
     /*
      * Backpointer to the full shared JSRuntime* with which this
      * thread is associated.  This is private because accessing the
      * fields of this runtime can provoke race conditions, so the
      * intention is that access will be mediated through safe
      * functions like |runtimeFromMainThread| and |associatedWith()| below.
      */
     JSRuntime *runtime_;
@@ -502,122 +507,24 @@ class PerThreadData : public PerThreadDa
         void *thing;
         JSGCTraceKind kind;
 
         SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
     };
     js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
 #endif
 
-    /*
-     * If Baseline or Ion code is on the stack, and has called into C++, this
-     * will be aligned to an exit frame.
-     */
-    uint8_t             *jitTop;
-
-    /*
-     * The current JSContext when entering JIT code. This field may only be used
-     * from JIT code and C++ directly called by JIT code (otherwise it may refer
-     * to the wrong JSContext).
-     */
-    JSContext           *jitJSContext;
-
-     /*
-     * Points to the most recent JitActivation pushed on the thread.
-     * See JitActivation constructor in vm/Stack.cpp
-     */
-    js::jit::JitActivation *jitActivation;
-
-    /* See comment for JSRuntime::interrupt_. */
-  private:
-    mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
-    void resetJitStackLimit();
-    friend struct ::JSRuntime;
-  public:
-    void initJitStackLimit();
-
-    uintptr_t jitStackLimit() const { return jitStackLimit_; }
-
-    // For read-only JIT use:
-    void *addressOfJitStackLimit() { return &jitStackLimit_; }
-    static size_t offsetOfJitStackLimit() { return offsetof(PerThreadData, jitStackLimit_); }
-
-    // Information about the heap allocated backtrack stack used by RegExp JIT code.
-    irregexp::RegExpStack regexpStack;
-
 #ifdef JS_TRACE_LOGGING
     TraceLoggerThread   *traceLogger;
 #endif
 
-  private:
-    friend class js::Activation;
-    friend class js::ActivationIterator;
-    friend class js::jit::JitActivation;
-    friend class js::AsmJSActivation;
-    friend class js::jit::CompileRuntime;
-#ifdef DEBUG
-    friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
-#endif
-
-    /*
-     * Points to the most recent activation running on the thread.
-     * See Activation comment in vm/Stack.h.
-     */
-    js::Activation *activation_;
-
-    /*
-     * Points to the most recent profiling activation running on the
-     * thread.
-     */
-    js::Activation * volatile profilingActivation_;
-
-    /* See AsmJSActivation comment. */
-    js::AsmJSActivation * volatile asmJSActivationStack_;
-
     /* Pointer to the current AutoFlushICache. */
     js::jit::AutoFlushICache *autoFlushICache_;
 
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-    js::jit::Simulator *simulator_;
-    uintptr_t simulatorStackLimit_;
-#endif
-
   public:
-    js::Activation *const *addressOfActivation() const {
-        return &activation_;
-    }
-    static unsigned offsetOfAsmJSActivationStackReadOnly() {
-        return offsetof(PerThreadData, asmJSActivationStack_);
-    }
-    static unsigned offsetOfActivation() {
-        return offsetof(PerThreadData, activation_);
-    }
-
-    js::Activation *profilingActivation() const {
-        return profilingActivation_;
-    }
-    void *addressOfProfilingActivation() {
-        return (void*) &profilingActivation_;
-    }
-    static unsigned offsetOfProfilingActivation() {
-        return offsetof(PerThreadData, profilingActivation_);
-    }
-
-    js::AsmJSActivation *asmJSActivationStack() const {
-        return asmJSActivationStack_;
-    }
-    static js::AsmJSActivation *innermostAsmJSActivation() {
-        PerThreadData *ptd = TlsPerThreadData.get();
-        return ptd ? ptd->asmJSActivationStack_ : nullptr;
-    }
-
-    js::Activation *activation() const {
-        return activation_;
-    }
-
     /* State used by jsdtoa.cpp. */
     DtoaState           *dtoaState;
 
     /*
      * When this flag is non-zero, any attempt to GC will be skipped. It is used
      * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in
      * debugging facilities that cannot tolerate a GC and would rather OOM
      * immediately, such as utilities exposed to GDB. Setting this flag is
@@ -654,42 +561,30 @@ class PerThreadData : public PerThreadDa
         PerThreadData *pt;
 
       public:
         AutoEnterRuntime(PerThreadData *pt, JSRuntime *rt)
           : pt(pt)
         {
             MOZ_ASSERT(!pt->runtime_);
             pt->runtime_ = rt;
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-            // The simulator has a pointer to its SimulatorRuntime, but helper threads
-            // don't have a simulator as they don't run JIT code so this pointer need not
-            // be updated. All the paths that the helper threads use access the
-            // SimulatorRuntime via the PerThreadData.
-            MOZ_ASSERT(!pt->simulator_);
-#endif
         }
 
         ~AutoEnterRuntime() {
             pt->runtime_ = nullptr;
-#if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
-            // Check that helper threads have not run JIT code and/or added a simulator.
-            MOZ_ASSERT(!pt->simulator_);
-#endif
         }
     };
 
     js::jit::AutoFlushICache *autoFlushICache() const;
     void setAutoFlushICache(js::jit::AutoFlushICache *afc);
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
     js::jit::Simulator *simulator() const;
     void setSimulator(js::jit::Simulator *sim);
     js::jit::SimulatorRuntime *simulatorRuntime() const;
-    uintptr_t *addressOfSimulatorStackLimit();
 #endif
 };
 
 class AutoLockForExclusiveAccess;
 
 } // namespace js
 
 struct JSRuntime : public JS::shadow::Runtime,
@@ -703,16 +598,107 @@ struct JSRuntime : public JS::shadow::Ru
      *
      * NB: This field is statically asserted to be at offset
      * sizeof(js::shadow::Runtime). See
      * PerThreadDataFriendFields::getMainThread.
      */
     js::PerThreadData mainThread;
 
     /*
+     * If Baseline or Ion code is on the stack, and has called into C++, this
+     * will be aligned to an exit frame.
+     */
+    uint8_t             *jitTop;
+
+    /*
+     * The current JSContext when entering JIT code. This field may only be used
+     * from JIT code and C++ directly called by JIT code (otherwise it may refer
+     * to the wrong JSContext).
+     */
+    JSContext           *jitJSContext;
+
+     /*
+     * Points to the most recent JitActivation pushed on the thread.
+     * See JitActivation constructor in vm/Stack.cpp
+     */
+    js::jit::JitActivation *jitActivation;
+
+    /* See comment for JSRuntime::interrupt_. */
+  private:
+    mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
+    void resetJitStackLimit();
+
+  public:
+    void initJitStackLimit();
+
+    uintptr_t jitStackLimit() const { return jitStackLimit_; }
+
+    // For read-only JIT use:
+    void *addressOfJitStackLimit() { return &jitStackLimit_; }
+    static size_t offsetOfJitStackLimit() { return offsetof(JSRuntime, jitStackLimit_); }
+
+    // Information about the heap allocated backtrack stack used by RegExp JIT code.
+    js::irregexp::RegExpStack regexpStack;
+
+  private:
+    friend class js::Activation;
+    friend class js::ActivationIterator;
+    friend class js::jit::JitActivation;
+    friend class js::AsmJSActivation;
+    friend class js::jit::CompileRuntime;
+#ifdef DEBUG
+    friend void js::AssertCurrentThreadCanLock(js::RuntimeLock which);
+#endif
+
+    /*
+     * Points to the most recent activation running on the thread.
+     * See Activation comment in vm/Stack.h.
+     */
+    js::Activation *activation_;
+
+    /*
+     * Points to the most recent profiling activation running on the
+     * thread.
+     */
+    js::Activation * volatile profilingActivation_;
+
+    /* See AsmJSActivation comment. */
+    js::AsmJSActivation * volatile asmJSActivationStack_;
+
+  public:
+    js::Activation *const *addressOfActivation() const {
+        return &activation_;
+    }
+    static unsigned offsetOfActivation() {
+        return offsetof(JSRuntime, activation_);
+    }
+
+    js::Activation *profilingActivation() const {
+        return profilingActivation_;
+    }
+    void *addressOfProfilingActivation() {
+        return (void*) &profilingActivation_;
+    }
+    static unsigned offsetOfProfilingActivation() {
+        return offsetof(JSRuntime, profilingActivation_);
+    }
+
+    js::AsmJSActivation *asmJSActivationStack() const {
+        return asmJSActivationStack_;
+    }
+    static js::AsmJSActivation *innermostAsmJSActivation() {
+        js::PerThreadData *ptd = js::TlsPerThreadData.get();
+        return ptd ? ptd->runtimeFromMainThread()->asmJSActivationStack_ : nullptr;
+    }
+
+    js::Activation *activation() const {
+        return activation_;
+    }
+
+    /*
      * If non-null, another runtime guaranteed to outlive this one and whose
      * permanent data may be used by this one where possible.
      */
     JSRuntime *parentRuntime;
 
   private:
     mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
 
@@ -983,25 +969,30 @@ struct JSRuntime : public JS::shadow::Ru
         gc.lockGC();
     }
 
     void unlockGC() {
         gc.unlockGC();
     }
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
+    js::jit::Simulator *simulator_;
+    uintptr_t simulatorStackLimit_;
     js::jit::SimulatorRuntime *simulatorRuntime_;
 #endif
 
   public:
     void setNeedsIncrementalBarrier(bool needs) {
         needsIncrementalBarrier_ = needs;
     }
 
 #if defined(JS_ARM_SIMULATOR) || defined(JS_MIPS_SIMULATOR)
+    js::jit::Simulator *simulator() const;
+    void setSimulator(js::jit::Simulator *sim);
+    uintptr_t *addressOfSimulatorStackLimit();
     js::jit::SimulatorRuntime *simulatorRuntime() const;
     void setSimulatorRuntime(js::jit::SimulatorRuntime *srt);
 #endif
 
     /* Strong references on scripts held for PCCount profiling API. */
     js::ScriptAndCountsVector *scriptAndCountsVector;
 
     /* Well-known numbers held for use by this runtime's contexts. */
@@ -1433,17 +1424,17 @@ namespace js {
 // When entering JIT code, the calling JSContext* is stored into the thread's
 // PerThreadData. This function retrieves the JSContext with the pre-condition
 // that the caller is JIT code or C++ called directly from JIT code. This
 // function should not be called from arbitrary locations since the JSContext
 // may be the wrong one.
 static inline JSContext *
 GetJSContextFromJitCode()
 {
-    JSContext *cx = TlsPerThreadData.get()->jitJSContext;
+    JSContext *cx = js::TlsPerThreadData.get()->runtimeFromMainThread()->jitJSContext;
     MOZ_ASSERT(cx);
     return cx;
 }
 
 /*
  * Flags accompany script version data so that a) dynamically created scripts
  * can inherit their caller's compile-time properties and b) scripts can be
  * appropriately compared in the eval cache across global option changes. An
--- a/js/src/vm/SPSProfiler.cpp
+++ b/js/src/vm/SPSProfiler.cpp
@@ -94,19 +94,19 @@ SPSProfiler::enable(bool enabled)
      * jitcode for scripts with active frames on the stack.  These scripts need to have
      * their profiler state toggled so they behave properly.
      */
     jit::ToggleBaselineProfiling(rt, enabled);
 
     /* Update lastProfilingFrame to point to the top-most JS jit-frame currently on
      * stack.
      */
-    if (rt->mainThread.jitActivation) {
-        void *lastProfilingFrame = GetTopProfilingJitFrame(rt->mainThread.jitTop);
-        rt->mainThread.jitActivation->setLastProfilingFrame(lastProfilingFrame);
+    if (rt->jitActivation) {
+        void *lastProfilingFrame = GetTopProfilingJitFrame(rt->jitTop);
+        rt->jitActivation->setLastProfilingFrame(lastProfilingFrame);
     }
 }
 
 /* Lookup the string for the function/script, creating one if necessary */
 const char*
 SPSProfiler::profileString(JSScript *script, JSFunction *maybeFun)
 {
     AutoSPSLock lock(lock_);
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -28,31 +28,16 @@ StackBaseShape::StackBaseShape(Exclusive
                                JSObject *parent, JSObject *metadata, uint32_t objectFlags)
   : flags(objectFlags),
     clasp(clasp),
     parent(parent),
     metadata(metadata),
     compartment(cx->compartment_)
 {}
 
-inline bool
-Shape::get(JSContext* cx, HandleObject receiver, JSObject* obj, JSObject *pobj,
-           MutableHandleValue vp)
-{
-    MOZ_ASSERT(!hasDefaultGetter());
-
-    if (hasGetterValue()) {
-        Value fval = getterValue();
-        return InvokeGetterOrSetter(cx, receiver, fval, 0, 0, vp);
-    }
-
-    RootedId id(cx, propid());
-    return CallJSPropertyOp(cx, getterOp(), receiver, id, vp);
-}
-
 inline Shape *
 Shape::search(ExclusiveContext *cx, jsid id)
 {
     ShapeTable::Entry *_;
     return search(cx, this, id, &_);
 }
 
 inline bool
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -912,17 +912,16 @@ class Shape : public gc::TenuredCell
     {
         return base->unowned() == this->base()->unowned() &&
                maybeSlot() == aslot &&
                attrs == aattrs &&
                getter() == rawGetter &&
                setter() == rawSetter;
     }
 
-    bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp);
     bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp);
 
     BaseShape *base() const { return base_.get(); }
 
     bool hasSlot() const {
         return (attrs & JSPROP_SHARED) == 0;
     }
     uint32_t slot() const { MOZ_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -817,31 +817,31 @@ AbstractFramePtr::popWith(JSContext *cx)
         return;
     }
     asBaselineFrame()->popWith(cx);
 }
 
 Activation::Activation(JSContext *cx, Kind kind)
   : cx_(cx),
     compartment_(cx->compartment()),
-    prev_(cx->perThreadData->activation_),
+    prev_(cx->runtime_->activation_),
     prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr),
     savedFrameChain_(0),
     hideScriptedCallerCount_(0),
     kind_(kind)
 {
-    cx->perThreadData->activation_ = this;
+    cx->runtime_->activation_ = this;
 }
 
 Activation::~Activation()
 {
-    MOZ_ASSERT_IF(isProfiling(), this != cx_->perThreadData->profilingActivation_);
-    MOZ_ASSERT(cx_->perThreadData->activation_ == this);
+    MOZ_ASSERT_IF(isProfiling(), this != cx_->runtime()->profilingActivation_);
+    MOZ_ASSERT(cx_->runtime_->activation_ == this);
     MOZ_ASSERT(hideScriptedCallerCount_ == 0);
-    cx_->perThreadData->activation_ = prev_;
+    cx_->runtime_->activation_ = prev_;
 }
 
 bool
 Activation::isProfiling() const
 {
     if (isInterpreter())
         return asInterpreter()->isProfiling();
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1383,39 +1383,39 @@ jit::JitActivation::JitActivation(JSCont
     active_(active),
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
     bailoutData_(nullptr),
     lastProfilingFrame_(nullptr),
     lastProfilingCallSite_(nullptr)
 {
     if (active) {
-        prevJitTop_ = cx->mainThread().jitTop;
-        prevJitJSContext_ = cx->mainThread().jitJSContext;
-        prevJitActivation_ = cx->mainThread().jitActivation;
-        cx->mainThread().jitJSContext = cx;
-        cx->mainThread().jitActivation = this;
+        prevJitTop_ = cx->runtime()->jitTop;
+        prevJitJSContext_ = cx->runtime()->jitJSContext;
+        prevJitActivation_ = cx->runtime()->jitActivation;
+        cx->runtime()->jitJSContext = cx;
+        cx->runtime()->jitActivation = this;
 
         registerProfiling();
     } else {
         prevJitTop_ = nullptr;
         prevJitJSContext_ = nullptr;
         prevJitActivation_ = nullptr;
     }
 }
 
 jit::JitActivation::~JitActivation()
 {
     if (active_) {
         if (isProfiling())
             unregisterProfiling();
 
-        cx_->perThreadData->jitTop = prevJitTop_;
-        cx_->perThreadData->jitJSContext = prevJitJSContext_;
-        cx_->perThreadData->jitActivation = prevJitActivation_;
+        cx_->runtime()->jitTop = prevJitTop_;
+        cx_->runtime()->jitJSContext = prevJitJSContext_;
+        cx_->runtime()->jitActivation = prevJitActivation_;
     }
 
     // All reocvered value are taken from activation during the bailout.
     MOZ_ASSERT(ionRecovery_.empty());
 
     // The BailoutFrameInfo should have unregistered itself from the
     // JitActivations.
     MOZ_ASSERT(!bailoutData_);
@@ -1448,35 +1448,35 @@ jit::JitActivation::cleanBailoutData()
 // setActive() is inlined in GenerateFFIIonExit() with explicit masm instructions so
 // changes to the logic here need to be reflected in GenerateFFIIonExit() in the enable
 // and disable activation instruction sequences.
 void
 jit::JitActivation::setActive(JSContext *cx, bool active)
 {
     // Only allowed to deactivate/activate if activation is top.
     // (Not tested and will probably fail in other situations.)
-    MOZ_ASSERT(cx->mainThread().activation_ == this);
+    MOZ_ASSERT(cx->runtime()->activation_ == this);
     MOZ_ASSERT(active != active_);
 
     if (active) {
         *((volatile bool *) active_) = true;
-        prevJitTop_ = cx->mainThread().jitTop;
-        prevJitJSContext_ = cx->mainThread().jitJSContext;
-        prevJitActivation_ = cx->mainThread().jitActivation;
-        cx->mainThread().jitJSContext = cx;
-        cx->mainThread().jitActivation = this;
+        prevJitTop_ = cx->runtime()->jitTop;
+        prevJitJSContext_ = cx->runtime()->jitJSContext;
+        prevJitActivation_ = cx->runtime()->jitActivation;
+        cx->runtime()->jitJSContext = cx;
+        cx->runtime()->jitActivation = this;
 
         registerProfiling();
 
     } else {
         unregisterProfiling();
 
-        cx->mainThread().jitTop = prevJitTop_;
-        cx->mainThread().jitJSContext = prevJitJSContext_;
-        cx->mainThread().jitActivation = prevJitActivation_;
+        cx->runtime()->jitTop = prevJitTop_;
+        cx->runtime()->jitJSContext = prevJitJSContext_;
+        cx->runtime()->jitActivation = prevJitActivation_;
 
         *((volatile bool *) active_) = false;
     }
 }
 
 void
 jit::JitActivation::removeRematerializedFrame(uint8_t *top)
 {
@@ -1621,18 +1621,18 @@ AsmJSActivation::AsmJSActivation(JSConte
     // NB: this is a hack and can be removed once Ion switches over to
     // JS::ProfilingFrameIterator.
     if (cx->runtime()->spsProfiler.enabled())
         profiler_ = &cx->runtime()->spsProfiler;
 
     prevAsmJSForModule_ = module.activation();
     module.activation() = this;
 
-    prevAsmJS_ = cx->mainThread().asmJSActivationStack_;
-    cx->mainThread().asmJSActivationStack_ = this;
+    prevAsmJS_ = cx->runtime()->asmJSActivationStack_;
+    cx->runtime()->asmJSActivationStack_ = this;
 
     // Now that the AsmJSActivation is fully initialized, make it visible to
     // asynchronous profiling.
     registerProfiling();
 }
 
 AsmJSActivation::~AsmJSActivation()
 {
@@ -1640,19 +1640,19 @@ AsmJSActivation::~AsmJSActivation()
     unregisterProfiling();
 
     MOZ_ASSERT(fp_ == nullptr);
 
     MOZ_ASSERT(module_.activation() == this);
     module_.activation() = prevAsmJSForModule_;
 
     JSContext *cx = cx_->asJSContext();
-    MOZ_ASSERT(cx->mainThread().asmJSActivationStack_ == this);
+    MOZ_ASSERT(cx->runtime()->asmJSActivationStack_ == this);
 
-    cx->mainThread().asmJSActivationStack_ = prevAsmJS_;
+    cx->runtime()->asmJSActivationStack_ = prevAsmJS_;
 }
 
 InterpreterFrameIterator &
 InterpreterFrameIterator::operator++()
 {
     MOZ_ASSERT(!done());
     if (fp_ != activation_->entryFrame_) {
         pc_ = fp_->prevpc();
@@ -1665,45 +1665,43 @@ InterpreterFrameIterator::operator++()
     }
     return *this;
 }
 
 void
 Activation::registerProfiling()
 {
     MOZ_ASSERT(isProfiling());
-    cx_->perThreadData->profilingActivation_ = this;
+    cx_->runtime()->profilingActivation_ = this;
 }
 
 void
 Activation::unregisterProfiling()
 {
     MOZ_ASSERT(isProfiling());
-    MOZ_ASSERT(cx_->perThreadData->profilingActivation_ == this);
+    MOZ_ASSERT(cx_->runtime()->profilingActivation_ == this);
 
     // There may be a non-active jit activation in the linked list.  Skip past it.
     Activation *prevProfiling = prevProfiling_;
     while (prevProfiling && prevProfiling->isJit() && !prevProfiling->asJit()->isActive())
         prevProfiling = prevProfiling->prevProfiling_;
 
-    cx_->perThreadData->profilingActivation_ = prevProfiling;
+    cx_->runtime()->profilingActivation_ = prevProfiling;
 }
 
 ActivationIterator::ActivationIterator(JSRuntime *rt)
-  : jitTop_(rt->mainThread.jitTop),
-    activation_(rt->mainThread.activation_)
+  : jitTop_(rt->jitTop),
+    activation_(rt->activation_)
 {
     settle();
 }
 
 ActivationIterator::ActivationIterator(PerThreadData *perThreadData)
-  : jitTop_(perThreadData->jitTop),
-    activation_(perThreadData->activation_)
+  : ActivationIterator(perThreadData->runtimeFromMainThread())
 {
-    settle();
 }
 
 ActivationIterator &
 ActivationIterator::operator++()
 {
     MOZ_ASSERT(activation_);
     if (activation_->isJit() && activation_->asJit()->isActive())
         jitTop_ = activation_->asJit()->prevJitTop();
@@ -1718,17 +1716,17 @@ ActivationIterator::settle()
     // Stop at the next active activation. No need to update jitTop_, since
     // we don't iterate over an active jit activation.
     while (!done() && activation_->isJit() && !activation_->asJit()->isActive())
         activation_ = activation_->prev();
 }
 
 JS::ProfilingFrameIterator::ProfilingFrameIterator(JSRuntime *rt, const RegisterState &state)
   : rt_(rt),
-    activation_(rt->mainThread.profilingActivation()),
+    activation_(rt->profilingActivation()),
     savedPrevJitTop_(nullptr)
 {
     if (!activation_)
         return;
 
     // If profiler sampling is not enabled, skip.
     if (!rt_->isProfilerSamplingEnabled()) {
         activation_ = nullptr;
@@ -1790,17 +1788,17 @@ void
 JS::ProfilingFrameIterator::iteratorConstruct(const RegisterState &state)
 {
     MOZ_ASSERT(!done());
     MOZ_ASSERT(activation_->isAsmJS() || activation_->isJit());
 
     if (activation_->isAsmJS()) {
         new (storage_.addr()) AsmJSProfilingFrameIterator(*activation_->asAsmJS(), state);
         // Set savedPrevJitTop_ to the actual jitTop_ from the runtime.
-        savedPrevJitTop_ = activation_->cx()->perThreadData->jitTop;
+        savedPrevJitTop_ = activation_->cx()->runtime()->jitTop;
         return;
     }
 
     MOZ_ASSERT(activation_->asJit()->isActive());
     new (storage_.addr()) jit::JitProfilingFrameIterator(rt_, state);
 }
 
 void
--- a/js/xpconnect/tests/chrome/chrome.ini
+++ b/js/xpconnect/tests/chrome/chrome.ini
@@ -63,16 +63,17 @@ skip-if = buildapp == 'mulet'
 [test_bug932906.xul]
 [test_bug996069.xul]
 [test_bug1041626.xul]
 [test_bug1042436.xul]
 [test_bug1050049.html]
 [test_bug1065185.html]
 [test_bug1074863.html]
 [test_bug1092477.xul]
+[test_bug1124898.html]
 [test_xrayToJS.xul]
 skip-if = buildapp == 'mulet'
 [test_chrometoSource.xul]
 skip-if = buildapp == 'mulet'
 [test_cloneInto.xul]
 [test_cows.xul]
 skip-if = buildapp == 'mulet'
 [test_discardSystemSource.xul]
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_bug1124898.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1124898
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1124898</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1124898 **/
+  SimpleTest.waitForExplicitFinish();
+  var w = window.open("about:blank", "w", "chrome");
+  is(w.eval('typeof getAttention'), 'function', 'getAttention exists on regular chrome window');
+  is(w.eval('typeof messageManager'), 'object', 'messageManager exists on regular chrome window');
+  var contentURL = "http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html";
+  w.location = contentURL;
+  tryWindow();
+
+  function tryWindow() {
+    if (w.document.title != 'empty test page') {
+      info("Document not loaded yet - retrying");
+      SimpleTest.executeSoon(tryWindow);
+      return;
+    }
+    is(w.eval('typeof getAttention'), 'undefined', 'getAttention doesnt exist on content-in-chrome window');
+    is(w.eval('typeof messageManager'), 'undefined', 'messageManager doesnt exist on content-in-chrome window');
+    w.close();
+    SimpleTest.finish();
+  }
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1124898">Mozilla Bug 1124898</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/js/xpconnect/tests/mochitest/file_empty.html
+++ b/js/xpconnect/tests/mochitest/file_empty.html
@@ -1,2 +1,3 @@
 <!DOCTYPE html>
-<html><head></head><body><span id="text">Nothing to see here</span><iframe name="subframe"></iframe></body></html>
+<!-- Note: other tests throughout the tree depend on the layout of this, including the title. Don't make big changes without a try run. -->
+<html><head><title>empty test page</title></head><body><span id="text">Nothing to see here</span><iframe name="subframe"></iframe></body></html>
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -3730,20 +3730,16 @@ nsRegion nsDisplayOpacity::GetOpaqueRegi
   return nsRegion();
 }
 
 // nsDisplayOpacity uses layers for rendering
 already_AddRefed<Layer>
 nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
                              LayerManager* aManager,
                              const ContainerLayerParameters& aContainerParameters) {
-  if (mOpacity == 0 && mFrame->GetContent() &&
-      !nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) {
-    return nullptr;
-  }
   nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
     BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
                            aContainerParameters, nullptr);
   if (!container)
     return nullptr;
 
   container->SetOpacity(mOpacity);
   nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(container, aBuilder,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1943,27 +1943,16 @@ nsIFrame::BuildDisplayListForStackingCon
     return;
 
   // Replaced elements have their visibility handled here, because
   // they're visually atomic
   if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
     return;
 
   const nsStyleDisplay* disp = StyleDisplay();
-  // We can stop right away if this is a zero-opacity stacking context and
-  // we're painting, and we're not animating opacity. Don't do this
-  // if we're going to compute plugin geometry, since opacity-0 plugins
-  // need to have display items built for them.
-  if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
-      !aBuilder->WillComputePluginGeometry() &&
-      !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
-      !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) {
-    return;
-  }
-
   if (disp->mWillChangeBitField != 0) {
     aBuilder->AddToWillChangeBudget(this, GetSize());
   }
 
   nsRect dirtyRect = aDirtyRect;
 
   bool inTransform = aBuilder->IsInTransform();
   bool isTransformed = IsTransformed();
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1587,18 +1587,18 @@ skip-if(B2G) == 582476-1.svg 582476-1-re
 == 584699-1.html 584699-1-ref.html
 == 585598-2.xhtml 585598-2-ref.xhtml
 == 586400-1.html 586400-1-ref.html
 skip-if(B2G) fuzzy-if(d2d,52,1051) fuzzy-if(OSX==1008,129,1068) == 586683-1.html 586683-1-ref.html
 == 589615-1a.xhtml 589615-1-ref.html
 == 589615-1b.html 589615-1-ref.html
 == 589672-1.html 589672-1-ref.html
 != 589682-1.html 589682-1-notref.html
-skip-if(!browserIsRemote) == 593243-1.html 593243-1-ref.html # bug 593168
-skip-if(!browserIsRemote) == 593243-2.html 593243-2-ref.html # bug 593168
+skip-if(!asyncPanZoom) == 593243-1.html 593243-1-ref.html # bug 593168
+skip-if(!asyncPanZoom) == 593243-2.html 593243-2-ref.html # bug 593168
 == 593544-1.html 593544-1-ref.html
 random-if(Android) == 594333-1.html 594333-1-ref.html
 fuzzy-if(B2G,1,40000) == 594624-1.html 594624-1-ref.html
 == 594737-1.html 594737-1-ref.html
 == 597721-1.html 597721-1-ref.html
 random-if(winWidget) fuzzy-if(B2G,3,40) fuzzy-if(Android,38,539) needs-focus == 598726-1.html 598726-1-ref.html # Fails on Windows, bug 782196
 == 599113-1.html 599113-1-ref.html
 fails-if(!haveTestPlugin) == 599476.html 599476-ref.html
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -85,17 +85,16 @@ skip-if(B2G||B2GDT) != page-height-2in.h
 # Check that tests that need focus are skipped when it's not available
 needs-focus load needs-focus.html
 
 # Bug 632636
 fails == data:text/plain,HELLO about:blank
 needs-focus == data:text/plain, about:blank
 
 # Sanity check of viewport+displayport overrides
-random-if(!browserIsRemote) == test-displayport.html test-displayport-ref.html # bug 593168
 skip-if(!browserIsRemote) != test-displayport-2.html test-displayport-ref.html # bug 593168
 skip-if(!browserIsRemote) fails-if(OSX&&layersGPUAccelerated) fuzzy-if(layersOMTC,1,1390) random-if(Android&&AndroidVersion<15) random-if(B2G||B2GDT) == 647192-1.html 647192-1-ref.html
 skip-if(!browserIsRemote||(B2G&&browserIsRemote)) == 656041-1.html 656041-1-ref.html
 skip-if(!browserIsRemote||layersOMTC) == test-displayport-bg.html test-displayport-ref.html # bug 694706
 
 # IPC Position-fixed frames/layers test
 # Fixed layers are temporarily disabled (bug 656167).
 #skip-if(!browserIsRemote) == test-pos-fixed.html test-pos-fixed-ref.html
deleted file mode 100644
--- a/layout/reftests/reftest-sanity/test-displayport.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<html reftest-viewport-w="100" reftest-viewport-h="100"
-      reftest-displayport-w="800" reftest-displayport-h="1000">
-<body>
-  <div style="position: absolute; left:0px; top:0px;width:800px; height:1000px; background:green;"></div>
-</body>
-</html>
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -566,16 +566,22 @@ pref("apz.test.logging_enabled", false);
 #ifdef XP_MACOSX
 // Whether to run in native HiDPI mode on machines with "Retina"/HiDPI display;
 //   <= 0 : hidpi mode disabled, display will just use pixel-based upscaling
 //   == 1 : hidpi supported if all screens share the same backingScaleFactor
 //   >= 2 : hidpi supported even with mixed backingScaleFactors (somewhat broken)
 pref("gfx.hidpi.enabled", 2);
 #endif
 
+#if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID)
+// Containerless scrolling for root frames does not yet pass tests on Android
+// or B2G.
+pref("layout.scroll.root-frame-containers", false);
+#endif
+
 // Whether to enable LayerScope tool and default listening port
 pref("gfx.layerscope.enabled", false);
 pref("gfx.layerscope.port", 23456);
 
 // Log severe performance warnings to the error console and profiles.
 // This should be use to quickly find which slow paths are used by test cases.
 pref("gfx.perf-warnings.enabled", false);
 
--- a/python/mozbuild/mozbuild/virtualenv.py
+++ b/python/mozbuild/mozbuild/virtualenv.py
@@ -390,16 +390,18 @@ class VirtualenvManager(object):
         """Activate the virtualenv in this Python context.
 
         If you run a random Python script and wish to "activate" the
         virtualenv, you can simply instantiate an instance of this class
         and call .ensure() and .activate() to make the virtualenv active.
         """
 
         execfile(self.activate_path, dict(__file__=self.activate_path))
+        if isinstance(os.environ['PATH'], unicode):
+            os.environ['PATH'] = os.environ['PATH'].encode('utf-8')
 
     def install_pip_package(self, package):
         """Install a package via pip.
 
         The supplied package is specified using a pip requirement specifier.
         e.g. 'foo' or 'foo==1.0'.
 
         If the package is already installed, this is a no-op.
--- a/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
+++ b/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
@@ -42,17 +42,17 @@ public:
                       Input, /*out*/ TrustLevel& trustLevel)
                       /*non-final*/ override
   {
     EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
     trustLevel = TrustLevel::InheritsTrust;
     return Success;
   }
 
-  Result FindIssuer(Input, IssuerChecker&, Time)
+  Result FindIssuer(Input, IssuerChecker&, Time) final override
   {
     ADD_FAILURE();
     return Result::FATAL_ERROR_LIBRARY_FAILURE;
   }
 
   Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&, Time time,
                          /*optional*/ const Input*, /*optional*/ const Input*)
                          final override
--- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
+++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
@@ -167,17 +167,17 @@ SandboxBroker::SetSecurityLevelForGMPlug
   if (!mPolicy) {
     return false;
   }
 
   auto result = mPolicy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
   bool ret = (sandbox::SBOX_ALL_OK == result);
   result =
     mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                           sandbox::USER_RESTRICTED);
+                           sandbox::USER_LOCKDOWN);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
 
   result = mPolicy->SetAlternateDesktop(true);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
 
   result = mPolicy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
   ret = ret && (sandbox::SBOX_ALL_OK == result);
 
--- a/testing/marionette/client/marionette/geckoinstance.py
+++ b/testing/marionette/client/marionette/geckoinstance.py
@@ -144,20 +144,35 @@ class GeckoInstance(object):
         self.close(restart=True)
         if prefs:
             self.prefs = prefs
         else:
             self.prefs = None
         self.start()
 
 class B2GDesktopInstance(GeckoInstance):
-    required_prefs = {"focusmanager.testmode": True}
-
-    def __init__(self, **kwargs):
-        super(B2GDesktopInstance, self).__init__(**kwargs)
+    def __init__(self, host, port, bin, **kwargs):
+        # Pass a profile and change the binary to -bin so that
+        # the built-in gaia profile doesn't get touched.
+        if kwargs.get('profile', None) is None:
+            # GeckoInstance.start will clone the profile.
+            kwargs['profile'] = os.path.join(os.path.dirname(bin),
+                                             'gaia',
+                                             'profile')
+        if '-bin' not in os.path.basename(bin):
+            if bin.endswith('.exe'):
+                newbin = bin[:-len('.exe')] + '-bin.exe'
+            else:
+                newbin = bin + '-bin'
+            if os.path.exists(newbin):
+                bin = newbin
+        super(B2GDesktopInstance, self).__init__(host, port, bin, **kwargs)
+        if not self.prefs:
+            self.prefs = {}
+        self.prefs["focusmanager.testmode"] = True
         self.app_args += ['-chrome', 'chrome://b2g/content/shell.html']
 
 class NullOutput(object):
     def __call__(self, line):
         pass
 
 
 apps = {'b2g': B2GDesktopInstance,
--- a/testing/marionette/client/marionette/marionette_test.py
+++ b/testing/marionette/client/marionette/marionette_test.py
@@ -190,16 +190,22 @@ class MetaParameterized(type):
                     if wrapper.__name__ in attrs:
                         raise KeyError("%s is already a defined method on %s" %
                                         (wrapper.__name__, name))
                     attrs[wrapper.__name__] = wrapper
                 del attrs[k]
 
         return type.__new__(cls, name, bases, attrs)
 
+class JSTest:
+    head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
+    context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
+    timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
+    inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
+
 class CommonTestCase(unittest.TestCase):
 
     __metaclass__ = MetaParameterized
     match_re = None
     failureException = AssertionError
 
     def __init__(self, methodName, **kwargs):
         unittest.TestCase.__init__(self, methodName)
@@ -481,16 +487,119 @@ setReq.onerror = function() {
         if not result:
             raise Exception('Failed to close Test Container app')
 
         Wait(self.marionette, timeout=10, interval=0.2).until(element_not_present(
             'css selector',
             'iframe[src*="app://test-container.gaiamobile.org/index.html"]'
         ))
 
+    def run_js_test(self, filename, marionette=None):
+        '''
+        Run a JavaScript test file and collect its set of assertions
+        into the current test's results.
+
+        :param filename: The path to the JavaScript test file to execute.
+                         May be relative to the current script.
+        :param marionette: The Marionette object in which to execute the test.
+                           Defaults to self.marionette.
+        '''
+        marionette = marionette or self.marionette
+        if not os.path.isabs(filename):
+            # Find the caller's filename and make the path relative to that.
+            caller_file = sys._getframe(1).f_globals.get('__file__', '')
+            caller_file = os.path.abspath(caller_file)
+            filename = os.path.join(os.path.dirname(caller_file), filename)
+        self.assert_(os.path.exists(filename),
+                     'Script "%s" must exist' % filename)
+        original_test_name = self.marionette.test_name
+        self.marionette.test_name = os.path.basename(filename)
+        f = open(filename, 'r')
+        js = f.read()
+        args = []
+
+        head_js = JSTest.head_js_re.search(js);
+        if head_js:
+            head_js = head_js.group(3)
+            head = open(os.path.join(os.path.dirname(filename), head_js), 'r')
+            js = head.read() + js;
+
+        context = JSTest.context_re.search(js)
+        if context:
+            context = context.group(3)
+        else:
+            context = 'content'
+        marionette.set_context(context)
+
+        if context != 'chrome':
+            marionette.navigate('data:text/html,<html>test page</html>')
+
+        timeout = JSTest.timeout_re.search(js)
+        if timeout:
+            timeout = timeout.group(3)
+            marionette.set_script_timeout(timeout)
+
+        inactivity_timeout = JSTest.inactivity_timeout_re.search(js)
+        if inactivity_timeout:
+            inactivity_timeout = inactivity_timeout.group(3)
+
+        try:
+            results = marionette.execute_js_script(
+                js,
+                args,
+                special_powers=True,
+                inactivity_timeout=inactivity_timeout,
+                filename=os.path.basename(filename)
+            )
+
+            self.assertTrue(not 'timeout' in filename,
+                            'expected timeout not triggered')
+
+            if 'fail' in filename:
+                self.assertTrue(len(results['failures']) > 0,
+                                "expected test failures didn't occur")
+            else:
+                for failure in results['failures']:
+                    diag = "" if failure.get('diag') is None else failure['diag']
+                    name = "got false, expected true" if failure.get('name') is None else failure['name']
+                    self.logger.test_status(self.test_name, name, 'FAIL',
+                                            message=diag)
+                for failure in results['expectedFailures']:
+                    diag = "" if failure.get('diag') is None else failure['diag']
+                    name = "got false, expected false" if failure.get('name') is None else failure['name']
+                    self.logger.test_status(self.test_name, name, 'FAIL',
+                                            expected='FAIL', message=diag)
+                for failure in results['unexpectedSuccesses']:
+                    diag = "" if failure.get('diag') is None else failure['diag']
+                    name = "got true, expected false" if failure.get('name') is None else failure['name']
+                    self.logger.test_status(self.test_name, name, 'PASS',
+                                            expected='FAIL', message=diag)
+                self.assertEqual(0, len(results['failures']),
+                                 '%d tests failed' % len(results['failures']))
+                if len(results['unexpectedSuccesses']) > 0:
+                    raise _UnexpectedSuccess('')
+                if len(results['expectedFailures']) > 0:
+                    raise _ExpectedFailure((AssertionError, AssertionError(''), None))
+
+            self.assertTrue(results['passed']
+                            + len(results['failures'])
+                            + len(results['expectedFailures'])
+                            + len(results['unexpectedSuccesses']) > 0,
+                            'no tests run')
+
+        except ScriptTimeoutException:
+            if 'timeout' in filename:
+                # expected exception
+                pass
+            else:
+                self.loglines = marionette.get_logs()
+                raise
+        self.marionette.test_name = original_test_name
+
+
 
 class MarionetteTestCase(CommonTestCase):
 
     match_re = re.compile(r"test_(.*)\.py$")
 
     def __init__(self, marionette_weakref, methodName='runTest',
                  filepath='', **kwargs):
         self._marionette_weakref = marionette_weakref
@@ -554,20 +663,16 @@ class MarionetteTestCase(CommonTestCase)
             if value:
                 return value
             time.sleep(0.5)
         else:
             raise TimeoutException("wait_for_condition timed out")
 
 class MarionetteJSTestCase(CommonTestCase):
 
-    head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
-    context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
-    timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
-    inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
     match_re = re.compile(r"test_(.*)\.js$")
 
     def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs):
         assert(jsFile)
         self.jsFile = jsFile
         self._marionette_weakref = marionette_weakref
         self.marionette = None
         self.test_container = kwargs.pop('test_container', None)
@@ -575,96 +680,19 @@ class MarionetteJSTestCase(CommonTestCas
 
     @classmethod
     def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, testvars, **kwargs):
         suite.addTest(cls(weakref.ref(marionette), jsFile=filepath, **kwargs))
 
     def runTest(self):
         if self.marionette.session is None:
             self.marionette.start_session()
-        self.marionette.test_name = os.path.basename(self.jsFile)
         self.marionette.execute_script("log('TEST-START: %s');" % self.jsFile.replace('\\', '\\\\'))
 
-        f = open(self.jsFile, 'r')
-        js = f.read()
-        args = []
-
-        if os.path.basename(self.jsFile).startswith('test_'):
-            head_js = self.head_js_re.search(js);
-            if head_js:
-                head_js = head_js.group(3)
-                head = open(os.path.join(os.path.dirname(self.jsFile), head_js), 'r')
-                js = head.read() + js;
-
-        context = self.context_re.search(js)
-        if context:
-            context = context.group(3)
-            self.marionette.set_context(context)
-
-        if context != "chrome":
-            self.marionette.navigate('data:text/html,<html>test page</html>')
-
-        timeout = self.timeout_re.search(js)
-        if timeout:
-            timeout = timeout.group(3)
-            self.marionette.set_script_timeout(timeout)
-
-        inactivity_timeout = self.inactivity_timeout_re.search(js)
-        if inactivity_timeout:
-            inactivity_timeout = inactivity_timeout.group(3)
-
-        try:
-            results = self.marionette.execute_js_script(js,
-                                                        args,
-                                                        special_powers=True,
-                                                        inactivity_timeout=inactivity_timeout,
-                                                        filename=os.path.basename(self.jsFile))
-
-            self.assertTrue(not 'timeout' in self.jsFile,
-                            'expected timeout not triggered')
-
-            if 'fail' in self.jsFile:
-                self.assertTrue(len(results['failures']) > 0,
-                                "expected test failures didn't occur")
-            else:
-                for failure in results['failures']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = "got false, expected true" if failure.get('name') is None else failure['name']
-                    self.logger.test_status(self.test_name, name, 'FAIL',
-                                            message=diag)
-                for failure in results['expectedFailures']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = "got false, expected false" if failure.get('name') is None else failure['name']
-                    self.logger.test_status(self.test_name, name, 'FAIL',
-                                            expected='FAIL', message=diag)
-                for failure in results['unexpectedSuccesses']:
-                    diag = "" if failure.get('diag') is None else failure['diag']
-                    name = "got true, expected false" if failure.get('name') is None else failure['name']
-                    self.logger.test_status(self.test_name, name, 'PASS',
-                                            expected='FAIL', message=diag)
-                self.assertEqual(0, len(results['failures']),
-                                 '%d tests failed' % len(results['failures']))
-                if len(results['unexpectedSuccesses']) > 0:
-                    raise _UnexpectedSuccess('')
-                if len(results['expectedFailures']) > 0:
-                    raise _ExpectedFailure((AssertionError, AssertionError(''), None))
-
-            self.assertTrue(results['passed']
-                            + len(results['failures'])
-                            + len(results['expectedFailures'])
-                            + len(results['unexpectedSuccesses']) > 0,
-                            'no tests run')
-
-        except ScriptTimeoutException:
-            if 'timeout' in self.jsFile:
-                # expected exception
-                pass
-            else:
-                self.loglines = self.marionette.get_logs()
-                raise
+        self.run_js_test(self.jsFile)
 
         self.marionette.execute_script("log('TEST-END: %s');" % self.jsFile.replace('\\', '\\\\'))
         self.marionette.test_name = None
 
     def get_test_class_name(self):
         # returns a dot separated folders as class name
         dirname = os.path.dirname(self.jsFile).replace('\\', '/')
         if dirname.startswith('/'):
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_run_js_test.py
@@ -0,0 +1,10 @@
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+from marionette_test import MarionetteTestCase
+import unittest
+
+class TestRunJSTest(MarionetteTestCase):
+    def test_basic(self):
+        self.run_js_test('test_simpletest_pass.js')
+        self.run_js_test('test_simpletest_fail.js')
--- a/testing/mozbase/mozrunner/tests/test_start.py
+++ b/testing/mozbase/mozrunner/tests/test_start.py
@@ -35,11 +35,11 @@ class MozrunnerStartTestCase(mozrunnerte
         self.runner.start(timeout=2)
         sleep(5)
 
         self.assertFalse(self.runner.is_running())
 
     def test_start_with_outputTimeout(self):
         """Start the process and set a timeout"""
         self.runner.start(outputTimeout=2)
-        sleep(5)
+        sleep(15)
 
         self.assertFalse(self.runner.is_running())
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,16 +1,16 @@
 {
     "talos.zip": {
         "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.f3179facd945.zip",
         "path": ""
     },
     "global": {
         "talos_repo": "https://hg.mozilla.org/build/talos",
-        "talos_revision": "ebc4327b8cb8"
+        "talos_revision": "bfd694ae4242"
     },
     "extra_options": {
         "android": [ "--apkPath=%(apk_path)s" ]
     },
     "suites": {
         "chromez": {
             "tests": ["tresize", "tcanvasmark"]
         },
@@ -34,17 +34,18 @@
         },
         "other": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"]
         },
         "other-snow": {
             "tests": ["tpaint"]
         },
         "other-snow-e10s": {
-            "tests": ["tpaint"]
+            "tests": ["tpaint"],
+            "talos_options": ["--e10s"]
         },
         "other_nol64": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"]
         },
         "other-e10s_nol64": {
             "tests": ["a11yr", "ts_paint", "tpaint", "sessionrestore", "sessionrestore_no_auto_restore"],
             "talos_options": ["--e10s"]
         },
@@ -75,30 +76,32 @@
                 "32": "http://talos-bundles.pvt.build.mozilla.org/zips/flash32_10_3_183_5.zip",
                 "64": "http://talos-bundles.pvt.build.mozilla.org/zips/flash64_11_0_d1_98.zip"
             }
         },
         "g1-snow": {
             "tests": ["glterrain"]
         },
         "g1-snow-e10s": {
-            "tests": ["glterrain"]
+            "tests": ["glterrain"],
+            "talos_options": ["--e10s"]
         },
         "svgr": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"]
         },
         "svgr-e10s": {
             "tests": ["tsvgx", "tsvgr_opacity", "tart", "tscrollx", "cart"],
             "talos_options": ["--e10s"]
         },
         "svgr-snow": {
             "tests": ["tsvgx", "tscrollx"]
         },
         "svgr-snow-e10s": {
-            "tests": ["tsvgx", "tscrollx"]
+            "tests": ["tsvgx", "tscrollx"],
+            "talos_options": ["--e10s"]
         },
         "tp5o": {
             "tests": ["tp5o"],
             "pagesets_url": "http://talos-bundles.pvt.build.mozilla.org/zips/tp5n.zip",
             "pagesets_parent_dir_path": "talos/page_load_test/",
             "pagesets_manifest_path": "talos/page_load_test/tp5n/tp5o.manifest",
             "plugins": {
                 "32": "http://talos-bundles.pvt.build.mozilla.org/zips/flash32_10_3_183_5.zip",
--- a/testing/xpcshell/moz-spdy/moz-spdy.js
+++ b/testing/xpcshell/moz-spdy/moz-spdy.js
@@ -85,39 +85,26 @@ runlater.prototype = {
   }
 };
 
 function executeRunLater(arg) {
   arg.onTimeout();
 }
 
 function handleRequest(req, res) {
-  try {
-    realHandleRequest(req, res);
-  } catch (e) {
-    console.log("spdy server suffered unhandled exception. will restart " + e);
-    var p = webServer.address().port;
-    webServer.close();
-    webServer = spdy.createServer(options, handleRequest).listen(p, "0.0.0.0", 200, listenok);
-  }
-}
-
-function realHandleRequest(req, res) {
   var u = url.parse(req.url);
   var content = getHttpContent(u.pathname);
 
   if (req.streamID) {
     res.setHeader('X-Connection-Spdy', 'yes');
     res.setHeader('X-Spdy-StreamId', '' + req.streamID);
   } else {
     res.setHeader('X-Connection-Spdy', 'no');
   }
 
-console.log(u.pathname);
-
   if (u.pathname === '/750ms') {
     var rl = new runlater();
     rl.req = req;
     rl.resp = res;
     setTimeout(executeRunLater, 750, rl);
     return;
   }
 
--- a/testing/xpcshell/runxpcshelltests.py
+++ b/testing/xpcshell/runxpcshelltests.py
@@ -944,17 +944,17 @@ class XPCShellTests(object):
             def startServer(name, serverJs):
                 if os.path.exists(serverJs):
                     # OK, we found our SPDY server, let's try to get it running
                     self.log.info('Found %s at %s' % (name, serverJs))
                     try:
                         # We pipe stdin to node because the spdy server will exit when its
                         # stdin reaches EOF
                         process = Popen([nodeBin, serverJs], stdin=PIPE, stdout=PIPE,
-                                stderr=STDOUT, env=self.env, cwd=os.getcwd())
+                                stderr=PIPE, env=self.env, cwd=os.getcwd())
                         self.nodeProc[name] = process
 
                         # Check to make sure the server starts properly by waiting for it to
                         # tell us it's started
                         msg = process.stdout.readline()
                         if 'server listening' in msg:
                             nodeMozInfo['hasNode'] = True
                             searchObj = re.search( r'SPDY server listening on port (.*)', msg, 0)
@@ -974,17 +974,29 @@ class XPCShellTests(object):
         mozinfo.update(nodeMozInfo)
 
     def shutdownNode(self):
         """
           Shut down our node process, if it exists
         """
         for name, proc in self.nodeProc.iteritems():
             self.log.info('Node %s server shutting down ...' % name)
-            proc.terminate()
+            if proc.poll() is not None:
+                self.log.info('Node server %s already dead %s' % (name, proc.poll()))
+            else:
+                proc.terminate()
+            def dumpOutput(fd, label):
+                firstTime = True
+                for msg in fd:
+                    if firstTime:
+                        firstTime = False;
+                        self.log.info('Process %s' % label)
+                    self.log.info(msg)
+            dumpOutput(proc.stdout, "stdout")
+            dumpOutput(proc.stderr, "stderr")
 
     def buildXpcsRunArgs(self):
         """
           Add arguments to run the test or make it interactive.
         """
         if self.interactive:
             self.xpcsRunArgs = [
             '-e', 'print("To start the test, type |_execute_test();|.");',
--- a/toolkit/content/tests/chrome/test_focus_anons.xul
+++ b/toolkit/content/tests/chrome/test_focus_anons.xul
@@ -1,14 +1,14 @@
 <?xml version="1.0"?>
 <?xml-stylesheet href="chrome://global/skin" type="text/css"?>
 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
 
 <window title="Tests for focus on elements with anonymous focusable children"
-        onload="setTimeout(runTests, 0);"
+        onload="SimpleTest.waitForFocus(runTests);"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>      
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>      
 
 <label accesskey="a" control="menulist"/>
 <label accesskey="b" control="textbox"/>
 <label accesskey="c" control="scale"/>
--- a/toolkit/locales/l10n.mk
+++ b/toolkit/locales/l10n.mk
@@ -108,29 +108,31 @@ repackage-zip:  libs-$(AB_CD)
 # call a hook for apps to put their uninstall helper.exe into the package
 	$(UNINSTALLER_PACKAGE_HOOK)
 # call a hook for apps to build the stub installer
 ifdef MOZ_STUB_INSTALLER
 	$(STUB_HOOK)
 endif
 	$(PYTHON) $(MOZILLA_DIR)/toolkit/mozapps/installer/l10n-repack.py $(STAGEDIST) $(DIST)/xpi-stage/locale-$(AB_CD) \
 		$(if $(filter omni,$(MOZ_PACKAGER_FORMAT)),$(if $(NON_OMNIJAR_FILES),--non-resource $(NON_OMNIJAR_FILES)))
-ifneq (en,$(AB))
+
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+ifneq (en,$(AB))
 	mv $(STAGEDIST)/en.lproj $(STAGEDIST)/$(AB).lproj
+endif
 ifdef MOZ_CRASHREPORTER
 # On Mac OS X, the crashreporter.ini file needs to be moved from under the
 # application bundle's Resources directory where all other l10n files are
 # located to the crash reporter bundle's Resources directory.
 	mv $(STAGEDIST)/crashreporter.app/Contents/Resources/crashreporter.ini \
 	  $(STAGEDIST)/../MacOS/crashreporter.app/Contents/Resources/crashreporter.ini
 	$(RM) -rf $(STAGEDIST)/crashreporter.app
 endif
 endif
-endif
+
 	$(NSINSTALL) -D $(DIST)/l10n-stage/$(PKG_PATH)
 	cd $(DIST)/l10n-stage; \
 	  $(MAKE_PACKAGE)
 ifdef MAKE_COMPLETE_MAR
 	$(MAKE) -C $(MOZDEPTH)/tools/update-packaging full-update AB_CD=$(AB_CD) \
 	  MOZ_PKG_PRETTYNAMES=$(MOZ_PKG_PRETTYNAMES) \
 	  PACKAGE_BASE_DIR='$(_ABS_DIST)/l10n-stage' \
 	  DIST='$(_ABS_DIST)'
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -17,16 +17,19 @@
 #include <pango/pango-fontmap.h>
 
 #include <fontconfig/fontconfig.h>
 #include "gfxPlatformGtk.h"
 
 #include "gtkdrawing.h"
 #include "nsStyleConsts.h"
 #include "gfxFontConstants.h"
+
+#include <dlfcn.h>
+
 #include "mozilla/gfx/2D.h"
 
 using mozilla::LookAndFeel;
 
 #define GDK_COLOR_TO_NS_RGB(c) \
     ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
 #define GDK_RGBA_TO_NS_RGBA(c) \
     ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \
@@ -728,16 +731,26 @@ GetSystemFontInfo(GtkWidget *aWidget,
 
     // |size| is now either pixels or pango-points (not Mozilla-points!)
 
     if (!pango_font_description_get_size_is_absolute(desc)) {
         // |size| is in pango-points, so convert to pixels.
         size *= float(gfxPlatformGtk::GetDPI()) / POINTS_PER_INCH_FLOAT;
     }
 
+    // Scale fonts up on HiDPI displays.
+    // This would be done automatically with cairo, but we manually manage
+    // the display scale for platform consistency.
+    static auto sGdkScreenGetMonitorScaleFactorPtr = (gint (*)(GdkScreen*,gint))
+        dlsym(RTLD_DEFAULT, "gdk_screen_get_monitor_scale_factor");
+    if (sGdkScreenGetMonitorScaleFactorPtr) {
+        GdkScreen *screen = gdk_screen_get_default();
+        size *= (*sGdkScreenGetMonitorScaleFactorPtr)(screen, 0);
+    }
+
     // |size| is now pixels
 
     aFontStyle->size = size;
 
     pango_font_description_free(desc);
 }
 
 static void
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -118,16 +118,18 @@ extern "C" {
   
 #include "nsShmImage.h"
 
 #include "nsIDOMWheelEvent.h"
 
 #include "NativeKeyBindings.h"
 #include "nsWindow.h"
 
+#include <dlfcn.h>
+
 #include "mozilla/layers/APZCTreeManager.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::widget;
 using namespace mozilla::layers;
 using mozilla::gl::GLContext;
 
@@ -468,16 +470,19 @@ nsWindow::DispatchResized(int32_t aWidth
 
 nsresult
 nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
 {
 #ifdef DEBUG
     debug_DumpEvent(stdout, aEvent->widget, aEvent,
                     nsAutoCString("something"), 0);
 #endif
+    // Translate the mouse event into device pixels.
+    aEvent->refPoint.x = GdkCoordToDevicePixels(aEvent->refPoint.x);
+    aEvent->refPoint.y = GdkCoordToDevicePixels(aEvent->refPoint.y);
 
     aStatus = nsEventStatus_eIgnore;
     nsIWidgetListener* listener =
         mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
     if (listener) {
       aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
     }
 
@@ -726,16 +731,22 @@ nsWindow::GetDPI()
     double heightInches = DisplayHeightMM(dpy, defaultScreen)/MM_PER_INCH_FLOAT;
     if (heightInches < 0.25) {
         // Something's broken, but we'd better not crash.
         return 96.0f;
     }
     return float(DisplayHeight(dpy, defaultScreen)/heightInches);
 }
 
+double
+nsWindow::GetDefaultScaleInternal()
+{
+    return GdkScaleFactor();
+}
+
 NS_IMETHODIMP
 nsWindow::SetParent(nsIWidget *aNewParent)
 {
     if (mContainer || !mGdkWindow) {
         NS_NOTREACHED("nsWindow::SetParent called illegally");
         return NS_ERROR_NOT_IMPLEMENTED;
     }
 
@@ -824,18 +835,19 @@ nsWindow::ReparentNativeWidgetInternal(n
             SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
 
             if (aOldContainer == gInvisibleContainer) {
                 CheckDestroyInvisibleContainer();
             }
         }
 
         if (!mIsTopLevel) {
-            gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
-                                mBounds.y);
+            gdk_window_reparent(mGdkWindow, aNewParentWindow,
+                                DevicePixelsToGdkCoordRoundDown(mBounds.x),
+                                DevicePixelsToGdkCoordRoundDown(mBounds.y));
         }
     }
 
     nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
     bool parentHasMappedToplevel =
         newParent && newParent->mHasMappedToplevel;
     if (mHasMappedToplevel != parentHasMappedToplevel) {
         SetHasMappedToplevel(parentHasMappedToplevel);
@@ -860,52 +872,56 @@ nsWindow::IsVisible() const
 {
     return mIsShown;
 }
 
 NS_IMETHODIMP
 nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
 {
     if (mIsTopLevel && mShell) {
-        int32_t screenWidth = gdk_screen_width();
-        int32_t screenHeight = gdk_screen_height();
+        int width = GdkCoordToDevicePixels(gdk_screen_width());
+        int height = GdkCoordToDevicePixels(gdk_screen_height());
         if (aAllowSlop) {
             if (*aX < (kWindowPositionSlop - mBounds.width))
                 *aX = kWindowPositionSlop - mBounds.width;
-            if (*aX > (screenWidth - kWindowPositionSlop))
-                *aX = screenWidth - kWindowPositionSlop;
+            if (*aX > (width - kWindowPositionSlop))
+                *aX = width - kWindowPositionSlop;
             if (*aY < (kWindowPositionSlop - mBounds.height))
                 *aY = kWindowPositionSlop - mBounds.height;
-            if (*aY > (screenHeight - kWindowPositionSlop))
-                *aY = screenHeight - kWindowPositionSlop;
+            if (*aY > (height - kWindowPositionSlop))
+                *aY = height - kWindowPositionSlop;
         } else {
             if (*aX < 0)
                 *aX = 0;
-            if (*aX > (screenWidth - mBounds.width))
-                *aX = screenWidth - mBounds.width;
+            if (*aX > (width - mBounds.width))
+                *aX = width - mBounds.width;
             if (*aY < 0)
                 *aY = 0;
-            if (*aY > (screenHeight - mBounds.height))
-                *aY = screenHeight - mBounds.height;
+            if (*aY > (height - mBounds.height))
+                *aY = height - mBounds.height;
         }
     }
     return NS_OK;
 }
 
 void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
 {
     mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
     mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
 
     if (mShell) {
         GdkGeometry geometry;
-        geometry.min_width = mSizeConstraints.mMinSize.width;
-        geometry.min_height = mSizeConstraints.mMinSize.height;
-        geometry.max_width = mSizeConstraints.mMaxSize.width;
-        geometry.max_height = mSizeConstraints.mMaxSize.height;
+        geometry.min_width = DevicePixelsToGdkCoordRoundUp(
+                             mSizeConstraints.mMinSize.width);
+        geometry.min_height = DevicePixelsToGdkCoordRoundUp(
+                              mSizeConstraints.mMinSize.height);
+        geometry.max_width = DevicePixelsToGdkCoordRoundDown(
+                             mSizeConstraints.mMaxSize.width);
+        geometry.max_height = DevicePixelsToGdkCoordRoundDown(
+                              mSizeConstraints.mMaxSize.height);
 
         uint32_t hints = GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
         gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
                                       &geometry, GdkWindowHints(hints));
     }
 }
 
 NS_IMETHODIMP
@@ -1158,21 +1174,23 @@ nsWindow::Move(double aX, double aY)
     mBounds.x = x;
     mBounds.y = y;
 
     if (!mCreated)
         return NS_OK;
 
     mNeedsMove = false;
 
+    GdkPoint point = DevicePixelsToGdkPointRoundDown(nsIntPoint(x, y));
+
     if (mIsTopLevel) {
-        gtk_window_move(GTK_WINDOW(mShell), x, y);
+        gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
     }
     else if (mGdkWindow) {
-        gdk_window_move(mGdkWindow, x, y);
+        gdk_window_move(mGdkWindow, point.x, point.y);
     }
 
     NotifyRollupGeometryChange();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement  aPlacement,
@@ -1429,17 +1447,17 @@ nsWindow::SetFocus(bool aRaise)
 
 NS_IMETHODIMP
 nsWindow::GetScreenBounds(nsIntRect &aRect)
 {
     if (mIsTopLevel && mContainer) {
         // use the point including window decorations
         gint x, y;
         gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
-        aRect.MoveTo(x, y);
+        aRect.MoveTo(GdkPointToDevicePixels({ x, y }));
     }
     else {
         aRect.MoveTo(WidgetToScreenOffset());
     }
     // mBounds.Size() is the window bounds, not the window-manager frame
     // bounds (bug 581863).  gdk_window_get_frame_extents would give the
     // frame bounds, but mBounds.Size() is returned here for consistency
     // with Resize.
@@ -1599,27 +1617,22 @@ nsWindow::SetCursor(imgIContainer* aCurs
 }
 
 NS_IMETHODIMP
 nsWindow::Invalidate(const nsIntRect &aRect)
 {
     if (!mGdkWindow)
         return NS_OK;
 
-    GdkRectangle rect;
-    rect.x = aRect.x;
-    rect.y = aRect.y;
-    rect.width = aRect.width;
-    rect.height = aRect.height;
+    GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
+    gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
 
     LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
              rect.x, rect.y, rect.width, rect.height));
 
-    gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
-
     return NS_OK;
 }
 
 void*
 nsWindow::GetNativeData(uint32_t aDataType)
 {
     switch (aDataType) {
     case NS_NATIVE_WINDOW:
@@ -1747,17 +1760,17 @@ nsIntPoint
 nsWindow::WidgetToScreenOffset()
 {
     gint x = 0, y = 0;
 
     if (mGdkWindow) {
         gdk_window_get_origin(mGdkWindow, &x, &y);
     }
 
-    return nsIntPoint(x, y);
+    return GdkPointToDevicePixels({ x, y });
 }
 
 NS_IMETHODIMP
 nsWindow::EnableDragDrop(bool aEnable)
 {
     return NS_OK;
 }
 
@@ -2039,17 +2052,19 @@ nsWindow::OnExposeEvent(cairo_t *cr)
 #if (MOZ_WIDGET_GTK == 2)
     if (!exposeRegion.Init(aEvent)) {
 #else
     if (!exposeRegion.Init(cr)) {
 #endif
         return FALSE;
     }
 
-    nsIntRegion &region = exposeRegion.mRegion;
+    gint scale = GdkScaleFactor();
+    nsIntRegion& region = exposeRegion.mRegion;
+    region.ScaleRoundOut(scale, scale);
 
     ClientLayerManager *clientLayers =
         (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT)
         ? static_cast<ClientLayerManager*>(GetLayerManager())
         : nullptr;
 
     if (clientLayers && mCompositorParent) {
         // We need to paint to the screen even if nothing changed, since if we
@@ -2379,31 +2394,34 @@ nsWindow::OnContainerUnrealize()
 
 void
 nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
 {
     LOG(("size_allocate [%p] %d %d %d %d\n",
          (void *)this, aAllocation->x, aAllocation->y,
          aAllocation->width, aAllocation->height));
 
-    nsIntSize size(aAllocation->width, aAllocation->height);
+    nsIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
+
     if (mBounds.Size() == size)
         return;
 
+    nsIntRect rect;
+
     // Invalidate the new part of the window now for the pending paint to
     // minimize background flashes (GDK does not do this for external resizes
     // of toplevels.)
     if (mBounds.width < size.width) {
-        GdkRectangle rect =
-            { mBounds.width, 0, size.width - mBounds.width, size.height };
+        GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
+            { mBounds.width, 0, size.width - mBounds.width, size.height });
         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
     }
     if (mBounds.height < size.height) {
-        GdkRectangle rect =
-            { 0, mBounds.height, size.width, size.height - mBounds.height };
+        GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
+            { 0, mBounds.height, size.width, size.height - mBounds.height });
         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
     }
 
     mBounds.SizeTo(size);
 
     if (!mGdkWindow)
         return;
 
@@ -3856,67 +3874,75 @@ nsWindow::SetWindowClass(const nsAString
   nsMemory::Free(res_name);
 
   return NS_OK;
 }
 
 void
 nsWindow::NativeResize(int32_t aWidth, int32_t aHeight, bool    aRepaint)
 {
+    gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
+    gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
+    
     LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
-         aWidth, aHeight));
+         width, height));
 
     // clear our resize flag
     mNeedsResize = false;
 
     if (mIsTopLevel) {
-        gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
+        gtk_window_resize(GTK_WINDOW(mShell), width, height);
     }
     else if (mContainer) {
         GtkWidget *widget = GTK_WIDGET(mContainer);
         GtkAllocation allocation, prev_allocation;
         gtk_widget_get_allocation(widget, &prev_allocation);
         allocation.x = prev_allocation.x;
         allocation.y = prev_allocation.y;
-        allocation.width = aWidth;
-        allocation.height = aHeight;
+        allocation.width = width;
+        allocation.height = height;
         gtk_widget_size_allocate(widget, &allocation);
     }
     else if (mGdkWindow) {
-        gdk_window_resize(mGdkWindow, aWidth, aHeight);
+        gdk_window_resize(mGdkWindow, width, height);
     }
 }
 
 void
 nsWindow::NativeResize(int32_t aX, int32_t aY,
                        int32_t aWidth, int32_t aHeight,
                        bool    aRepaint)
 {
+    gint width = DevicePixelsToGdkCoordRoundUp(aWidth);
+    gint height = DevicePixelsToGdkCoordRoundUp(aHeight);
+    gint x = DevicePixelsToGdkCoordRoundDown(aX);
+    gint y = DevicePixelsToGdkCoordRoundDown(aY);
+
     mNeedsResize = false;
     mNeedsMove = false;
 
     LOG(("nsWindow::NativeResize [%p] %d %d %d %d\n", (void *)this,
-         aX, aY, aWidth, aHeight));
+         x, y, width, height));
 
     if (mIsTopLevel) {
-        // aX and aY give the position of the window manager frame top-left.
-        gtk_window_move(GTK_WINDOW(mShell), aX, aY);
+        // x and y give the position of the window manager frame top-left.
+        gtk_window_move(GTK_WINDOW(mShell), x, y);
         // This sets the client window size.
-        gtk_window_resize(GTK_WINDOW(mShell), aWidth, aHeight);
+        gtk_window_resize(GTK_WINDOW(mShell), width, height);
     }
     else if (mContainer) {
         GtkAllocation allocation;
-        allocation.x = aX;
-        allocation.y = aY;
-        allocation.width = aWidth;
-        allocation.height = aHeight;
+        allocation.x = x;
+        allocation.y = y;
+        allocation.width = width;
+        allocation.height = height;
         gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
     }
     else if (mGdkWindow) {
-        gdk_window_move_resize(mGdkWindow, aX, aY, aWidth, aHeight);
+        gdk_window_move_resize(mGdkWindow, x, y, width, height);
     }
 }
 
 void
 nsWindow::NativeShow(bool aAction)
 {
     if (aAction) {
         // unset our flag now that our window has been shown
@@ -6186,18 +6212,18 @@ nsWindow::GetThebesSurface(cairo_t *cr)
         return nullptr;
 
 #ifdef MOZ_X11
     gint width, height;
 
 #if (MOZ_WIDGET_GTK == 2)
     gdk_drawable_get_size(GDK_DRAWABLE(mGdkWindow), &width, &height);
 #else
-    width = gdk_window_get_width(mGdkWindow);
-    height = gdk_window_get_height(mGdkWindow);
+    width = GdkCoordToDevicePixels(gdk_window_get_width(mGdkWindow));
+    height = GdkCoordToDevicePixels(gdk_window_get_height(mGdkWindow));
 #endif
 
     // Owen Taylor says this is the right thing to do!
     width = std::min(32767, width);
     height = std::min(32767, height);
     gfxIntSize size(width, height);
 
     GdkVisual *gdkVisual = gdk_window_get_visual(mGdkWindow);
@@ -6213,35 +6239,21 @@ nsWindow::GetThebesSurface(cairo_t *cr)
             nsShmImage::EnsureShmImage(size,
                                        visual, gdk_visual_get_depth(gdkVisual),
                                        mShmImage);
         usingShm = mThebesSurface != nullptr;
     }
     if (!usingShm)
 #  endif  // MOZ_HAVE_SHMIMAGE
     {
-#if (MOZ_WIDGET_GTK == 3)
-#if MOZ_TREE_CAIRO
-#error "cairo-gtk3 target must be built with --enable-system-cairo"
-#else    
-        if (cr) {
-            cairo_surface_t *surf = cairo_get_target(cr);
-            if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
-              NS_NOTREACHED("Missing cairo target?");
-              return nullptr;
-            }
-            mThebesSurface = gfxASurface::Wrap(surf);
-        } else
-#endif
-#endif // (MOZ_WIDGET_GTK == 3)
-            mThebesSurface = new gfxXlibSurface
-                (GDK_WINDOW_XDISPLAY(mGdkWindow),
-                 gdk_x11_window_get_xid(mGdkWindow),
-                 visual,
-                 size);
+        mThebesSurface = new gfxXlibSurface
+            (GDK_WINDOW_XDISPLAY(mGdkWindow),
+             gdk_x11_window_get_xid(mGdkWindow),
+             visual,
+             size);
     }
 #endif // MOZ_X11
 
     // if the surface creation is reporting an error, then
     // we don't have a surface to give back
     if (mThebesSurface && mThebesSurface->CairoStatus() != 0) {
         mThebesSurface = nullptr;
     }
@@ -6299,16 +6311,18 @@ nsWindow::BeginMoveDrag(WidgetMouseEvent
 
     GdkWindow *gdk_window;
     gint button, screenX, screenY;
     if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
         return NS_ERROR_FAILURE;
     }
 
     // tell the window manager to start the move
+    screenX = DevicePixelsToGdkCoordRoundDown(screenX);
+    screenY = DevicePixelsToGdkCoordRoundDown(screenY);
     gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
                                aEvent->time);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
@@ -6390,16 +6404,79 @@ nsWindow::ClearCachedResources()
     for (GList* list = children; list; list = list->next) {
         nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
         if (window) {
             window->ClearCachedResources();
         }
     }
 }
 
+gint
+nsWindow::GdkScaleFactor()
+{
+#if (MOZ_WIDGET_GTK >= 3)
+    // Available as of GTK 3.10+
+    static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
+        dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
+    if (sGdkWindowGetScaleFactorPtr)
+        return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
+#endif
+    return 1;
+}
+
+
+gint
+nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
+    gint scale = GdkScaleFactor();
+    return (pixels + scale - 1) / scale;
+}
+
+gint
+nsWindow::DevicePixelsToGdkCoordRoundDown(int pixels) {
+    gint scale = GdkScaleFactor();
+    return pixels / scale;
+}
+
+GdkPoint
+nsWindow::DevicePixelsToGdkPointRoundDown(nsIntPoint point) {
+    gint scale = GdkScaleFactor();
+    return { point.x / scale, point.y / scale };
+}
+
+GdkRectangle
+nsWindow::DevicePixelsToGdkRectRoundOut(nsIntRect rect) {
+    gint scale = GdkScaleFactor();
+    int x = rect.x / scale;
+    int y = rect.y / scale;
+    int right = (rect.x + rect.width + scale - 1) / scale;
+    int bottom = (rect.y + rect.height + scale - 1) / scale;
+    return { x, y, right - x, bottom - y };
+}
+
+int
+nsWindow::GdkCoordToDevicePixels(gint coord) {
+    return coord * GdkScaleFactor();
+}
+
+nsIntPoint
+nsWindow::GdkPointToDevicePixels(GdkPoint point) {
+    gint scale = GdkScaleFactor();
+    return nsIntPoint(point.x * scale,
+                      point.y * scale);
+}
+
+nsIntRect
+nsWindow::GdkRectToDevicePixels(GdkRectangle rect) {
+    gint scale = GdkScaleFactor();
+    return nsIntRect(rect.x * scale,
+                     rect.y * scale,
+                     rect.width * scale,
+                     rect.height * scale);
+}
+
 nsresult
 nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint,
                                      uint32_t aNativeMessage,
                                      uint32_t aModifierFlags)
 {
   if (!mGdkWindow) {
     return NS_OK;
   }
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -92,16 +92,17 @@ public:
     NS_IMETHOD         Create(nsIWidget        *aParent,
                               nsNativeWidget   aNativeParent,
                               const nsIntRect  &aRect,
                               nsDeviceContext *aContext,
                               nsWidgetInitData *aInitData) MOZ_OVERRIDE;
     NS_IMETHOD         Destroy(void) MOZ_OVERRIDE;
     virtual nsIWidget *GetParent() MOZ_OVERRIDE;
     virtual float      GetDPI() MOZ_OVERRIDE;
+    virtual double     GetDefaultScaleInternal() MOZ_OVERRIDE; 
     virtual nsresult   SetParent(nsIWidget* aNewParent) MOZ_OVERRIDE;
     NS_IMETHOD         SetModal(bool aModal) MOZ_OVERRIDE;
     virtual bool       IsVisible() const MOZ_OVERRIDE;
     NS_IMETHOD         ConstrainPosition(bool aAllowSlop,
                                          int32_t *aX,
                                          int32_t *aY) MOZ_OVERRIDE;
     virtual void       SetSizeConstraints(const SizeConstraints& aConstraints) MOZ_OVERRIDE;
     NS_IMETHOD         Move(double aX,
@@ -470,16 +471,30 @@ private:
      * The instance is created when the top level widget is created.  And when
      * the widget is destroyed, it's released.  All child windows refer its
      * ancestor widget's instance.  So, one set of IM contexts is created for
      * all windows in a hierarchy.  If the children are released after the top
      * level window is released, the children still have a valid pointer,
      * however, IME doesn't work at that time.
      */
     nsRefPtr<nsGtkIMModule> mIMModule;
+
+    // HiDPI scale conversion
+    gint GdkScaleFactor();
+
+    // To GDK
+    gint DevicePixelsToGdkCoordRoundUp(int pixels);
+    gint DevicePixelsToGdkCoordRoundDown(int pixels);
+    GdkPoint DevicePixelsToGdkPointRoundDown(nsIntPoint point);
+    GdkRectangle DevicePixelsToGdkRectRoundOut(nsIntRect rect);
+
+    // From GDK
+    int GdkCoordToDevicePixels(gint coord);
+    nsIntPoint GdkPointToDevicePixels(GdkPoint point);
+    nsIntRect GdkRectToDevicePixels(GdkRectangle rect);
 };
 
 class nsChildWindow : public nsWindow {
 public:
     nsChildWindow();
     ~nsChildWindow();
 };