Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Fri, 15 Jun 2018 12:49:01 +0300
changeset 422657 0b5495dc100d
parent 422629 dc997a4e045e (current diff)
parent 422656 31c7ebf5b949 (diff)
child 422659 5680d6b40b7f
child 422681 8e1ccac26253
push id34140
push useraciure@mozilla.com
push dateFri, 15 Jun 2018 09:49:23 +0000
treeherdermozilla-central@0b5495dc100d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
0b5495dc100d / 62.0a1 / 20180615100050 / files
nightly linux64
0b5495dc100d / 62.0a1 / 20180615100050 / files
nightly mac
0b5495dc100d / 62.0a1 / 20180615100050 / files
nightly win32
0b5495dc100d / 62.0a1 / 20180615100050 / files
nightly win64
0b5495dc100d / 62.0a1 / 20180615100050 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/base/nsINode.cpp
servo/components/style/gecko/media_queries.rs
servo/ports/geckolib/glue.rs
--- a/browser/themes/shared/sidebar.inc.css
+++ b/browser/themes/shared/sidebar.inc.css
@@ -99,17 +99,16 @@
 toolbarseparator + #sidebar-extensions-separator {
   display: none;
 }
 
 #sidebarMenu-popup > .subviewbutton[checked="true"] {
   list-style-image: none;
   background: url(chrome://browser/skin/check.svg) no-repeat transparent;
   background-size: 11px 11px;
-  color: var(--arrowpanel-color);
 }
 
 %ifdef XP_MACOSX
 
 #sidebarMenu-popup > .subviewbutton[checked="true"] {
   background-position: top 7px left 4px;
 }
 
--- a/docshell/base/nsDocShellTreeOwner.cpp
+++ b/docshell/base/nsDocShellTreeOwner.cpp
@@ -106,17 +106,16 @@ NS_IMPL_RELEASE(nsDocShellTreeOwner)
 
 NS_INTERFACE_MAP_BEGIN(nsDocShellTreeOwner)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocShellTreeOwner)
   NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner)
   NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
-  NS_INTERFACE_MAP_ENTRY(nsICDocShellTreeOwner)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END
 
 //*****************************************************************************
 // nsDocShellTreeOwner::nsIInterfaceRequestor
 //*****************************************************************************
 
 NS_IMETHODIMP
--- a/docshell/base/nsDocShellTreeOwner.h
+++ b/docshell/base/nsDocShellTreeOwner.h
@@ -34,38 +34,21 @@ namespace dom {
 class Event;
 class EventTarget;
 } // namespace dom
 } // namespace mozilla
 
 class nsWebBrowser;
 class ChromeTooltipListener;
 
-// {6D10C180-6888-11d4-952B-0020183BF181}
-#define NS_ICDOCSHELLTREEOWNER_IID \
-  { 0x6d10c180, 0x6888, 0x11d4, { 0x95, 0x2b, 0x0, 0x20, 0x18, 0x3b, 0xf1, 0x81 } }
-
-// This is a fake 'hidden' interface that nsDocShellTreeOwner implements.
-// Classes can QI for this interface to be sure that
-// they're dealing with a valid nsDocShellTreeOwner and not some other object
-// that implements nsIDocShellTreeOwner.
-class nsICDocShellTreeOwner : public nsISupports
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICDOCSHELLTREEOWNER_IID)
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsICDocShellTreeOwner, NS_ICDOCSHELLTREEOWNER_IID)
-
 class nsDocShellTreeOwner final : public nsIDocShellTreeOwner,
                                   public nsIBaseWindow,
                                   public nsIInterfaceRequestor,
                                   public nsIWebProgressListener,
                                   public nsIDOMEventListener,
-                                  public nsICDocShellTreeOwner,
                                   public nsSupportsWeakReference
 {
   friend class nsWebBrowser;
 
 public:
   NS_DECL_ISUPPORTS
 
   NS_DECL_NSIBASEWINDOW
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -4589,23 +4589,39 @@ nsINode::GetOwnerDocument() const
 }
 
 inline nsINode*
 nsINode::OwnerDocAsNode() const
 {
   return OwnerDoc();
 }
 
+// ShouldUseXBLScope is defined here as a template so that we can get the faster
+// version of IsInAnonymousSubtree if we're statically known to be an
+// nsIContent.  we could try defining ShouldUseXBLScope separately on nsINode
+// and nsIContent, but then we couldn't put its nsINode implementation here
+// (because this header does not include nsIContent) and we can't put it in
+// nsIContent.h, because the definition of nsIContent::IsInAnonymousSubtree is
+// in nsIContentInlines.h.  And then we get include hell from people trying to
+// call nsINode::GetParentObject but not including nsIContentInlines.h and with
+// no really good way to include it.
+template<typename T>
+inline bool ShouldUseXBLScope(const T* aNode)
+{
+  return aNode->IsInAnonymousSubtree() &&
+         !aNode->IsAnonymousContentInSVGUseSubtree();
+}
+
 inline mozilla::dom::ParentObject
 nsINode::GetParentObject() const
 {
   mozilla::dom::ParentObject p(OwnerDoc());
     // Note that mUseXBLScope is a no-op for chrome, and other places where we
     // don't use XBL scopes.
-  p.mUseXBLScope = IsInAnonymousSubtree() && !IsAnonymousContentInSVGUseSubtree();
+  p.mUseXBLScope = ShouldUseXBLScope(this);
   return p;
 }
 
 inline nsIDocument*
 nsINode::AsDocument()
 {
   MOZ_ASSERT(IsDocument());
   return static_cast<nsIDocument*>(this);
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -28,16 +28,17 @@
 #include "mozilla/dom/CharacterData.h"
 #include "mozilla/dom/DocumentType.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/L10nUtilsBinding.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/PromiseNativeHandler.h"
 #include "mozilla/dom/ShadowRoot.h"
+#include "mozilla/dom/ScriptSettings.h"
 #include "nsAttrValueOrString.h"
 #include "nsBindingManager.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsContentList.h"
 #include "nsContentUtils.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDocument.h"
@@ -1294,16 +1295,59 @@ CheckForOutdatedParent(nsINode* aParent,
     if (js::GetGlobalForObjectCrossCompartment(existingObj) !=
         global->GetGlobalJSObject()) {
       JSAutoRealm ar(cx, existingObj);
       ReparentWrapper(cx, existingObj, aError);
     }
   }
 }
 
+static nsresult
+ReparentWrappersInSubtree(nsIContent* aRoot)
+{
+  MOZ_ASSERT(ShouldUseXBLScope(aRoot));
+  // Start off with no global so we don't fire any error events on failure.
+  AutoJSAPI jsapi;
+  jsapi.Init();
+
+  JSContext* cx = jsapi.cx();
+
+  nsIGlobalObject* docGlobal = aRoot->OwnerDoc()->GetScopeObject();
+  if (NS_WARN_IF(!docGlobal)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  JS::Rooted<JSObject*> rootedGlobal(cx, docGlobal->GetGlobalJSObject());
+  if (NS_WARN_IF(!rootedGlobal)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  rootedGlobal = xpc::GetXBLScope(cx, rootedGlobal);
+
+  ErrorResult rv;
+  JS::Rooted<JSObject*> reflector(cx);
+  for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) {
+    if ((reflector = cur->GetWrapper())) {
+      JSAutoRealm ar(cx, reflector);
+      ReparentWrapper(cx, reflector, rv);
+      rv.WouldReportJSException();
+      if (rv.Failed()) {
+        // We _could_ consider BlastSubtreeToPieces here, but it's not really
+        // needed.  Having some nodes in here accessible to content while others
+        // are not is probably OK.  We just need to fail out of the actual
+        // insertion, so they're not in the DOM.  Returning a failure here will
+        // do that.
+        return rv.StealNSResult();
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
 nsresult
 nsINode::doInsertChildAt(nsIContent* aKid, uint32_t aIndex,
                          bool aNotify, nsAttrAndChildArray& aChildArray)
 {
   MOZ_ASSERT(!aKid->GetParentNode(), "Inserting node that already has parent");
   MOZ_ASSERT(!IsAttr());
 
   // The id-handling code, and in the future possibly other code, need to
@@ -1345,19 +1389,25 @@ nsINode::doInsertChildAt(nsIContent* aKi
   nsresult rv = aChildArray.InsertChildAt(aKid, aIndex);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aIndex == 0) {
     mFirstChild = aKid;
   }
 
   nsIContent* parent = IsContent() ? AsContent() : nullptr;
 
+  bool wasInXBLScope = ShouldUseXBLScope(aKid);
   rv = aKid->BindToTree(doc, parent,
                         parent ? parent->GetBindingParent() : nullptr,
                         true);
+  if (NS_SUCCEEDED(rv) && !wasInXBLScope && ShouldUseXBLScope(aKid)) {
+    MOZ_ASSERT(ShouldUseXBLScope(this),
+               "Why does the kid need to use an XBL scope?");
+    rv = ReparentWrappersInSubtree(aKid);
+  }
   if (NS_FAILED(rv)) {
     if (GetFirstChild() == aKid) {
       mFirstChild = aKid->GetNextSibling();
     }
     aChildArray.RemoveChildAt(aIndex);
     aKid->UnbindFromTree();
     return rv;
   }
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -561,17 +561,17 @@ private:
   // The thread that created this TErrorResult
   NS_DECL_OWNINGTHREAD;
 #endif
 
   // Not to be implemented, to make sure people always pass this by
   // reference, not by value.
   TErrorResult(const TErrorResult&) = delete;
   void operator=(const TErrorResult&) = delete;
-};
+} JS_HAZ_ROOTED;
 
 struct JustAssertCleanupPolicy {
   static const bool assertHandled = true;
   static const bool suppress = false;
   static const bool assertSameThread = true;
 };
 
 struct AssertAndSuppressCleanupPolicy {
@@ -833,17 +833,17 @@ class MOZ_TEMPORARY_CLASS IgnoreErrors {
 public:
   operator ErrorResult&() && { return mInner; }
   operator OOMReporter&() && { return mInner; }
 private:
   // We don't use an ErrorResult member here so we don't make two separate calls
   // to SuppressException (one from us, one from the ErrorResult destructor
   // after asserting).
   binding_danger::TErrorResult<binding_danger::JustSuppressCleanupPolicy> mInner;
-};
+} JS_HAZ_ROOTED;
 
 /******************************************************************************
  ** Macros for checking results
  ******************************************************************************/
 
 #define ENSURE_SUCCESS(res, ret)                                          \
   do {                                                                    \
     if (res.Failed()) {                                                   \
--- a/dom/bindings/test/test_dom_xrays.html
+++ b/dom/bindings/test/test_dom_xrays.html
@@ -270,16 +270,24 @@ function test()
         "Should see constant property on interface objects");
   isnot(typeof elem.ELEMENT_NODE, "undefined",
         "Should see constant property on prototype objects");
   is(Object.getOwnPropertyDescriptor(elem, "ELEMENT_NODE"), undefined,
      "Shouldn't see constant property on instances");
   isnot(typeof Object.getOwnPropertyDescriptor(win.Node.prototype, "ELEMENT_NODE"), "undefined",
         "Should see constant property on prototype objects");
 
+  // Adopting nodes should not lose expandos.
+  var elem = doc.createElement("span");
+  elem.expando = 5;
+  is(elem.expando, 5, "We just set this property");
+  document.adoptNode(elem);
+  is(elem.wrappedJSObject, undefined, "Shouldn't be an Xray anymore");
+  is(elem.expando, 5, "Expando should not get lost");
+
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(test);
 
 </script>
 </pre>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -229,16 +229,18 @@ EventStateManager::DeltaAccumulator*
   EventStateManager::DeltaAccumulator::sInstance = nullptr;
 
 EventStateManager::EventStateManager()
   : mLockCursor(0)
   , mLastFrameConsumedSetCursor(false)
   , mCurrentTarget(nullptr)
     // init d&d gesture state machine variables
   , mGestureDownPoint(0,0)
+  , mGestureModifiers(0)
+  , mGestureDownButtons(0)
   , mPresContext(nullptr)
   , mLClickCount(0)
   , mMClickCount(0)
   , mRClickCount(0)
   , mInTouchDrag(false)
   , m_haveShutdown(false)
 {
   if (sESMInstanceCount == 0) {
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -193,16 +193,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
 
 IMEContentObserver::IMEContentObserver()
   : mESM(nullptr)
   , mIMENotificationRequests(nullptr)
+  , mPreAttrChangeLength(0)
   , mSuppressNotifications(0)
   , mPreCharacterDataChangeLength(-1)
   , mSendingNotification(NOTIFY_IME_OF_NOTHING)
   , mIsObserving(false)
   , mIMEHasFocus(false)
   , mNeedsToNotifyIMEOfFocusSet(false)
   , mNeedsToNotifyIMEOfTextChange(false)
   , mNeedsToNotifyIMEOfSelectionChange(false)
--- a/dom/events/TextComposition.h
+++ b/dom/events/TextComposition.h
@@ -572,16 +572,17 @@ private:
     RefPtr<TextComposition> mTextComposition;
     nsCOMPtr<nsINode> mEventTarget;
     nsString mData;
     EventMessage mEventMessage;
     bool mIsSynthesizedEvent;
 
     CompositionEventDispatcher()
       : Runnable("TextComposition::CompositionEventDispatcher")
+      , mEventMessage(eVoidEvent)
       , mIsSynthesizedEvent(false){};
   };
 
   /**
    * DispatchCompositionEventRunnable() dispatches a composition event to the
    * content.  Be aware, if you use this method, nsPresShellEventCB isn't used.
    * That means that nsIFrame::HandleEvent() is never called.
    * WARNING: The instance which is managed by IMEStateManager may be
--- a/dom/events/WheelHandlingHelper.h
+++ b/dom/events/WheelHandlingHelper.h
@@ -275,16 +275,20 @@ class MOZ_STACK_CLASS WheelDeltaHorizont
 {
 public:
   /**
    * @param aWheelEvent        A wheel event whose delta values will be adjusted
    *                           upon calling Horizontalize().
    */
   explicit WheelDeltaHorizontalizer(WidgetWheelEvent& aWheelEvent)
     : mWheelEvent(aWheelEvent)
+    , mOldDeltaX(0.0)
+    , mOldDeltaZ(0.0)
+    , mOldOverflowDeltaX(0.0)
+    , mOldLineOrPageDeltaX(0)
     , mHorizontalized(false)
   {
   }
   /**
    * Converts vertical scrolling into horizontal scrolling by adjusting the
    * its delta values.
    */
   void Horizontalize();
--- a/dom/events/XULCommandEvent.cpp
+++ b/dom/events/XULCommandEvent.cpp
@@ -11,16 +11,17 @@ namespace mozilla {
 namespace dom {
 
 XULCommandEvent::XULCommandEvent(EventTarget* aOwner,
                                  nsPresContext* aPresContext,
                                  WidgetInputEvent* aEvent)
   : UIEvent(aOwner, aPresContext,
             aEvent ? aEvent :
                      new WidgetInputEvent(false, eVoidEvent, nullptr))
+  , mInputSource(0)
 {
   if (aEvent) {
     mEventIsInternal = false;
   }
   else {
     mEventIsInternal = true;
     mEvent->mTime = PR_Now();
   }
--- a/dom/filesystem/FileSystemTaskBase.h
+++ b/dom/filesystem/FileSystemTaskBase.h
@@ -183,16 +183,17 @@ private:
 
 // This class is the 'alter ego' of FileSystemTaskChildBase in the PBackground
 // world.
 class FileSystemTaskParentBase : public Runnable
 {
 public:
   FileSystemTaskParentBase()
     : Runnable("FileSystemTaskParentBase")
+    , mErrorValue(NS_ERROR_NOT_INITIALIZED)
   {}
 
   /*
    * Start the task. This must be called from the PBackground thread only.
    */
   void
   Start();
 
--- a/gfx/webrender_bindings/RenderThread.cpp
+++ b/gfx/webrender_bindings/RenderThread.cpp
@@ -35,16 +35,17 @@ RenderThread::RenderThread(base::Thread*
   , mHasShutdown(false)
   , mHandlingDeviceReset(false)
 {
 
 }
 
 RenderThread::~RenderThread()
 {
+  MOZ_ASSERT(mRenderTexturesDeferred.empty());
   delete mThread;
 }
 
 // static
 RenderThread*
 RenderThread::Get()
 {
   return sRenderThread;
@@ -502,19 +503,20 @@ RenderThread::UnregisterExternalImage(ui
     // deletion task here.
     // The shmem and raw buffer are owned by compositor ipc channel. It's
     // possible that RenderTextureHost is still exist after the shmem/raw buffer
     // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
     // for this situation. Gecko will only release the buffer if WR doesn't need
     // it. So, no one will access the invalid buffer in RenderTextureHost.
     RefPtr<RenderTextureHost> texture;
     mRenderTextures.Remove(aExternalImageId, getter_AddRefs(texture));
-    Loop()->PostTask(NewRunnableMethod<RefPtr<RenderTextureHost>>(
+    mRenderTexturesDeferred.emplace_back(std::move(texture));
+    Loop()->PostTask(NewRunnableMethod(
       "RenderThread::DeferredRenderTextureHostDestroy",
-      this, &RenderThread::DeferredRenderTextureHostDestroy, std::move(texture)
+      this, &RenderThread::DeferredRenderTextureHostDestroy
     ));
   } else {
     mRenderTextures.Remove(aExternalImageId);
   }
 }
 
 void
 RenderThread::UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId)
@@ -522,19 +524,20 @@ RenderThread::UnregisterExternalImageDur
   MOZ_ASSERT(IsInRenderThread());
   MutexAutoLock lock(mRenderTextureMapLock);
   MOZ_ASSERT(mHasShutdown);
   MOZ_ASSERT(mRenderTextures.GetWeak(aExternalImageId));
   mRenderTextures.Remove(aExternalImageId);
 }
 
 void
-RenderThread::DeferredRenderTextureHostDestroy(RefPtr<RenderTextureHost>)
+RenderThread::DeferredRenderTextureHostDestroy()
 {
-  // Do nothing. Just decrease the ref-count of RenderTextureHost.
+  MutexAutoLock lock(mRenderTextureMapLock);
+  mRenderTexturesDeferred.clear();
 }
 
 RenderTextureHost*
 RenderThread::GetRenderTexture(wr::WrExternalImageId aExternalImageId)
 {
   MOZ_ASSERT(IsInRenderThread());
 
   MutexAutoLock lock(mRenderTextureMapLock);
@@ -557,18 +560,22 @@ RenderThread::HandleDeviceReset(const ch
     return;
   }
 
   gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
   if (XRE_IsGPUProcess()) {
     gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
   }
 
-  for (auto iter = mRenderTextures.Iter(); !iter.Done(); iter.Next()) {
-    iter.UserData()->ClearCachedResources();
+  {
+    MutexAutoLock lock(mRenderTextureMapLock);
+    mRenderTexturesDeferred.clear();
+    for (auto iter = mRenderTextures.Iter(); !iter.Done(); iter.Next()) {
+      iter.UserData()->ClearCachedResources();
+    }
   }
 
   mHandlingDeviceReset = true;
   // All RenderCompositors will be destroyed by GPUChild::RecvNotifyDeviceReset()
 }
 
 bool
 RenderThread::IsHandlingDeviceReset()
--- a/gfx/webrender_bindings/RenderThread.h
+++ b/gfx/webrender_bindings/RenderThread.h
@@ -15,16 +15,18 @@
 #include "nsRefPtrHashtable.h"
 #include "ThreadSafeRefcountingWithMainThreadDestruction.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "mozilla/layers/SynchronousTask.h"
 
+#include <list>
+
 namespace mozilla {
 namespace wr {
 
 class RendererOGL;
 class RenderTextureHost;
 class RenderThread;
 
 /// A rayon thread pool that is shared by all WebRender instances within a process.
@@ -170,17 +172,17 @@ public:
   /// Can only be called from the render thread.
   bool IsHandlingDeviceReset();
 
   size_t RendererCount();
 
 private:
   explicit RenderThread(base::Thread* aThread);
 
-  void DeferredRenderTextureHostDestroy(RefPtr<RenderTextureHost> aTexture);
+  void DeferredRenderTextureHostDestroy();
   void ShutDownTask(layers::SynchronousTask* aTask);
   void ProgramCacheTask();
 
   ~RenderThread();
 
   base::Thread* const mThread;
 
   WebRenderThreadPool mThreadPool;
@@ -194,16 +196,20 @@ private:
     int64_t mRenderingCount = 0;
   };
 
   Mutex mFrameCountMapLock;
   nsDataHashtable<nsUint64HashKey, WindowInfo> mWindowInfos;
 
   Mutex mRenderTextureMapLock;
   nsRefPtrHashtable<nsUint64HashKey, RenderTextureHost> mRenderTextures;
+  // Used to remove all RenderTextureHost that are going to be removed by
+  // a deferred callback and remove them right away without waiting for the callback.
+  // On device reset we have to remove all GL related resources right away.
+  std::list<RefPtr<RenderTextureHost>> mRenderTexturesDeferred;
   bool mHasShutdown;
 
   bool mHandlingDeviceReset;
 };
 
 } // namespace wr
 } // namespace mozilla
 
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1485,24 +1485,31 @@ bool
 ModuleBuilder::processExportObjectBinding(frontend::ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Object));
     MOZ_ASSERT(pn->isArity(PN_LIST));
 
     for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
         MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
                    node->isKind(ParseNodeKind::Colon) ||
-                   node->isKind(ParseNodeKind::Shorthand));
+                   node->isKind(ParseNodeKind::Shorthand) ||
+                   node->isKind(ParseNodeKind::Spread));
 
-        ParseNode* target = node->isKind(ParseNodeKind::MutateProto)
-            ? node->pn_kid
-            : node->pn_right;
+        ParseNode* target;
+        if (node->isKind(ParseNodeKind::Spread)) {
+            target = node->pn_kid;
+        } else {
+            if (node->isKind(ParseNodeKind::MutateProto))
+                target = node->pn_kid;
+            else
+                target = node->pn_right;
 
-        if (target->isKind(ParseNodeKind::Assign))
-            target = target->pn_left;
+            if (target->isKind(ParseNodeKind::Assign))
+                target = target->pn_left;
+        }
 
         if (!processExportBinding(target))
             return false;
     }
 
     return true;
 }
 
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -317,29 +317,20 @@ function stripUCSAndNamespace(name)
 function extraRootedGCThings()
 {
     return [ 'JSAddonId' ];
 }
 
 function extraRootedPointers()
 {
     return [
-        'ModuleValidator',
-        'JSErrorResult',
-        'WrappableJSErrorResult',
-
         // These are not actually rooted, but are only used in the context of
         // AutoKeepAtoms.
         'js::frontend::TokenStream',
         'js::frontend::TokenStreamAnyChars',
-
-        'mozilla::ErrorResult',
-        'mozilla::IgnoredErrorResult',
-        'mozilla::IgnoreErrors',
-        'mozilla::dom::binding_detail::FastErrorResult',
     ];
 }
 
 function isRootedGCPointerTypeName(name)
 {
     name = stripUCSAndNamespace(name);
 
     if (name.startsWith('MaybeRooted<'))
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5434,24 +5434,31 @@ bool
 Parser<FullParseHandler, CharT>::checkExportedNamesForObjectBinding(ParseNode* pn)
 {
     MOZ_ASSERT(pn->isKind(ParseNodeKind::Object));
     MOZ_ASSERT(pn->isArity(PN_LIST));
 
     for (ParseNode* node = pn->pn_head; node; node = node->pn_next) {
         MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
                    node->isKind(ParseNodeKind::Colon) ||
-                   node->isKind(ParseNodeKind::Shorthand));
-
-        ParseNode* target = node->isKind(ParseNodeKind::MutateProto)
-            ? node->pn_kid
-            : node->pn_right;
-
-        if (target->isKind(ParseNodeKind::Assign))
-            target = target->pn_left;
+                   node->isKind(ParseNodeKind::Shorthand) ||
+                   node->isKind(ParseNodeKind::Spread));
+
+        ParseNode* target;
+        if (node->isKind(ParseNodeKind::Spread)) {
+            target = node->pn_kid;
+        } else {
+            if (node->isKind(ParseNodeKind::MutateProto))
+                target = node->pn_kid;
+            else
+                target = node->pn_right;
+
+            if (target->isKind(ParseNodeKind::Assign))
+                target = target->pn_left;
+        }
 
         if (!checkExportedNamesForDeclaration(target))
             return false;
     }
 
     return true;
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/auto-regress/bug1468629.js
@@ -0,0 +1,11 @@
+function lfEvalInCache(lfCode, lfIncremental = false, lfRunOnce = false) {
+  let ctx = {};
+  let code = cacheEntry(lfCode);
+  ctx_save = Object.create(ctx, { saveIncrementalBytecode: { value: true } });
+  try { evaluate(code, ctx_save); } catch(exc) {}
+  try { evaluate(code, Object.create(ctx_save, { loadBytecode: { value: true } })); } catch(exc) {}
+}
+lfEvalInCache(`
+  function q() {}
+  Object.freeze(this);
+`, false, true);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/modules/bug-1462286.js
@@ -0,0 +1,10 @@
+load(libdir + "dummyModuleResolveHook.js");
+
+let a = moduleRepo['a'] = parseModule(`
+  export var { ... get } = { x: "foo" };
+`);
+
+let m = parseModule("import { get } from 'a'; export { get };");
+m.declarationInstantiation();
+m.evaluation()
+assertEq(getModuleEnvironmentValue(m, "get").x, "foo");
--- a/js/src/vm/Scope.cpp
+++ b/js/src/vm/Scope.cpp
@@ -203,49 +203,53 @@ NewEmptyScopeData(JSContext* cx, uint32_
     if (!bytes)
         ReportOutOfMemory(cx);
     auto data = reinterpret_cast<typename ConcreteScope::Data*>(bytes);
     if (data)
         new (data) typename ConcreteScope::Data(length);
     return UniquePtr<typename ConcreteScope::Data>(data);
 }
 
+static constexpr size_t HasAtomMask = 1;
+static constexpr size_t HasAtomShift = 1;
+
 static XDRResult
 XDRBindingName(XDRState<XDR_ENCODE>* xdr, BindingName* bindingName)
 {
     JSContext* cx = xdr->cx();
 
     RootedAtom atom(cx, bindingName->name());
     bool hasAtom = !!atom;
 
-    uint8_t u8 = uint8_t(hasAtom << 1) | uint8_t(bindingName->closedOver());
+    uint8_t flags = bindingName->flagsForXDR();
+    MOZ_ASSERT(((flags << HasAtomShift) >> HasAtomShift) == flags);
+    uint8_t u8 = (flags << HasAtomShift) | uint8_t(hasAtom);
     MOZ_TRY(xdr->codeUint8(&u8));
 
     if (hasAtom)
         MOZ_TRY(XDRAtom(xdr, &atom));
 
     return Ok();
 }
 
 static XDRResult
 XDRBindingName(XDRState<XDR_DECODE>* xdr, BindingName* bindingName)
 {
     JSContext* cx = xdr->cx();
 
     uint8_t u8;
     MOZ_TRY(xdr->codeUint8(&u8));
 
-    bool closedOver = u8 & 1;
-    bool hasAtom = u8 >> 1;
-
+    bool hasAtom = u8 & HasAtomMask;
     RootedAtom atom(cx);
     if (hasAtom)
         MOZ_TRY(XDRAtom(xdr, &atom));
 
-    *bindingName = BindingName(atom, closedOver);
+    uint8_t flags = u8 >> HasAtomShift;
+    *bindingName = BindingName::fromXDR(atom, flags);
 
     return Ok();
 }
 
 template <typename ConcreteScopeData>
 static void
 DeleteScopeData(ConcreteScopeData* data)
 {
--- a/js/src/vm/Scope.h
+++ b/js/src/vm/Scope.h
@@ -125,16 +125,35 @@ class BindingName
     { }
 
     BindingName(JSAtom* name, bool closedOver, bool isTopLevelFunction = false)
       : bits_(uintptr_t(name) |
               (closedOver ? ClosedOverFlag : 0x0) |
               (isTopLevelFunction? TopLevelFunctionFlag : 0x0))
     { }
 
+  private:
+    // For fromXDR.
+    BindingName(JSAtom* name, uint8_t flags)
+      : bits_(uintptr_t(name) | flags)
+    {
+        static_assert(FlagMask < alignof(JSAtom),
+                      "Flags should fit into unused bits of JSAtom pointer");
+        MOZ_ASSERT((flags & FlagMask) == flags);
+    }
+
+  public:
+    static BindingName fromXDR(JSAtom* name, uint8_t flags) {
+        return BindingName(name, flags);
+    }
+
+    uint8_t flagsForXDR() const {
+        return static_cast<uint8_t>(bits_ & FlagMask);
+    }
+
     JSAtom* name() const {
         return reinterpret_cast<JSAtom*>(bits_ & ~FlagMask);
     }
 
     bool closedOver() const {
         return bits_ & ClosedOverFlag;
     }
 
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -1379,17 +1379,17 @@ static const unsigned VALIDATION_LIFO_DE
 // Rooting note: ModuleValidator is a stack class that contains unrooted
 // PropertyName (JSAtom) pointers.  This is safe because it cannot be
 // constructed without a TokenStream reference.  TokenStream is itself a stack
 // class that cannot be constructed without an AutoKeepAtoms being live on the
 // stack, which prevents collection of atoms.
 //
 // ModuleValidator is marked as rooted in the rooting analysis.  Don't add
 // non-JSAtom pointers, or this will break!
-class MOZ_STACK_CLASS ModuleValidator
+class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
 {
   public:
     class Func
     {
         PropertyName* name_;
         uint32_t sigIndex_;
         uint32_t firstUse_;
         uint32_t funcDefIndex_;
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -42,21 +42,29 @@ using mozilla::MakeEnumeratedRange;
 // We have only tested WASM_HUGE_MEMORY on x64 and arm64.
 
 #if defined(WASM_HUGE_MEMORY)
 #  if !(defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64))
 #    error "Not an expected configuration"
 #  endif
 #endif
 
-// Another sanity check.
+// More sanity checks.
 
 static_assert(MaxMemoryInitialPages <= ArrayBufferObject::MaxBufferByteLength / PageSize,
               "Memory sizing constraint");
 
+// All plausible targets must be able to do at least IEEE754 double
+// loads/stores, hence the lower limit of 8.  Some Intel processors support
+// AVX-512 loads/stores, hence the upper limit of 64.
+static_assert(MaxMemoryAccessSize >= 8,  "MaxMemoryAccessSize too low");
+static_assert(MaxMemoryAccessSize <= 64, "MaxMemoryAccessSize too high");
+static_assert((MaxMemoryAccessSize & (MaxMemoryAccessSize-1)) == 0,
+              "MaxMemoryAccessSize is not a power of two");
+
 void
 Val::writePayload(uint8_t* dst) const
 {
     switch (type_.code()) {
       case ValType::I32:
       case ValType::F32:
         memcpy(dst, &u.i32_, sizeof(u.i32_));
         return;
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -648,16 +648,17 @@ class Val
         memcpy(u.i32x4_, i32x4, sizeof(u.i32x4_));
     }
     explicit Val(const F32x4& f32x4) : type_(ValType::F32x4) {
         memcpy(u.f32x4_, f32x4, sizeof(u.f32x4_));
     }
 
     ValType type() const { return type_; }
     bool isSimd() const { return IsSimdType(type()); }
+    static constexpr size_t sizeofLargestValue() { return sizeof(u); }
 
     uint32_t i32() const { MOZ_ASSERT(type_ == ValType::I32); return u.i32_; }
     uint64_t i64() const { MOZ_ASSERT(type_ == ValType::I64); return u.i64_; }
     const float& f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; }
     const double& f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; }
 
     const I8x16& i8x16() const {
         MOZ_ASSERT(type_ == ValType::I8x16 || type_ == ValType::B8x16);
@@ -1988,17 +1989,17 @@ static const unsigned PageSize = 64 * 10
 
 // Bounds checks always compare the base of the memory access with the bounds
 // check limit. If the memory access is unaligned, this means that, even if the
 // bounds check succeeds, a few bytes of the access can extend past the end of
 // memory. To guard against this, extra space is included in the guard region to
 // catch the overflow. MaxMemoryAccessSize is a conservative approximation of
 // the maximum guard space needed to catch all unaligned overflows.
 
-static const unsigned MaxMemoryAccessSize = sizeof(Val);
+static const unsigned MaxMemoryAccessSize = Val::sizeofLargestValue();
 
 #ifdef WASM_HUGE_MEMORY
 
 // On WASM_HUGE_MEMORY platforms, every asm.js or WebAssembly memory
 // unconditionally allocates a huge region of virtual memory of size
 // wasm::HugeMappedSize. This allows all memory resizing to work without
 // reallocation and provides enough guard space for all offsets to be folded
 // into memory accesses.
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1262,33 +1262,61 @@ XrayTraits::ensureExpandoObject(JSContex
 bool
 XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject srcChain)
 {
     MOZ_ASSERT(js::IsObjectInContextCompartment(dst, cx));
     MOZ_ASSERT(getExpandoChain(dst) == nullptr);
 
     RootedObject oldHead(cx, srcChain);
     while (oldHead) {
+        // If movingIntoXrayCompartment is true, then our new reflector is in a
+        // compartment that used to have an Xray-with-expandos to the old reflector
+        // and we should copy the expandos to the new reflector directly.
+        bool movingIntoXrayCompartment;
+
+        // exclusiveWrapper is only used if movingIntoXrayCompartment ends up true.
         RootedObject exclusiveWrapper(cx);
         RootedObject wrapperHolder(cx, JS_GetReservedSlot(oldHead,
                                                           JSSLOT_EXPANDO_EXCLUSIVE_WRAPPER_HOLDER)
                                                          .toObjectOrNull());
         if (wrapperHolder) {
-            // The global containing this wrapper holder has an xray for |src|
-            // with expandos. Create an xray in the global for |dst| which
-            // will be associated with a clone of |src|'s expando object.
-            JSAutoRealm ar(cx, UncheckedUnwrap(wrapperHolder));
-            exclusiveWrapper = dst;
-            if (!JS_WrapObject(cx, &exclusiveWrapper))
+            RootedObject unwrappedHolder(cx, UncheckedUnwrap(wrapperHolder));
+            // unwrappedHolder is the compartment of the relevant Xray, so check
+            // whether that matches the compartment of cx (which matches the
+            // compartment of dst).
+            movingIntoXrayCompartment =
+                js::IsObjectInContextCompartment(unwrappedHolder, cx);
+
+            if (!movingIntoXrayCompartment) {
+                // The global containing this wrapper holder has an xray for |src|
+                // with expandos. Create an xray in the global for |dst| which
+                // will be associated with a clone of |src|'s expando object.
+                JSAutoRealm ar(cx, unwrappedHolder);
+                exclusiveWrapper = dst;
+                if (!JS_WrapObject(cx, &exclusiveWrapper))
+                    return false;
+            }
+        } else {
+            JSAutoRealm ar(cx, oldHead);
+            movingIntoXrayCompartment =
+                expandoObjectMatchesConsumer(cx, oldHead, ObjectPrincipal(dst));
+        }
+
+        if (movingIntoXrayCompartment) {
+            // Just copy properties directly onto dst.
+            if (!JS_CopyPropertiesFrom(cx, dst, oldHead))
+                return false;
+        } else {
+            // Create a new expando object in the compartment of dst to replace
+            // oldHead.
+            RootedObject newHead(cx, attachExpandoObject(cx, dst, exclusiveWrapper,
+                                                         GetExpandoObjectPrincipal(oldHead)));
+            if (!JS_CopyPropertiesFrom(cx, newHead, oldHead))
                 return false;
         }
-        RootedObject newHead(cx, attachExpandoObject(cx, dst, exclusiveWrapper,
-                                                     GetExpandoObjectPrincipal(oldHead)));
-        if (!JS_CopyPropertiesFrom(cx, newHead, oldHead))
-            return false;
         oldHead = JS_GetReservedSlot(oldHead, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
     }
     return true;
 }
 
 void
 ClearXrayExpandoSlots(JSObject* target, size_t slotIndex)
 {
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -840,17 +840,17 @@ nsMediaFeatures::features[] = {
     nsMediaFeature::eNoRequirements,
     { kOrientationKeywords },
     GetDeviceOrientation
   },
   {
     &nsGkAtoms::_moz_is_resource_document,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
-    nsMediaFeature::eNoRequirements,
+    nsMediaFeature::eUserAgentAndChromeOnly,
     { nullptr },
     GetIsResourceDocument
   },
   {
     &nsGkAtoms::_moz_scrollbar_start_backward,
     nsMediaFeature::eMinMaxNotAllowed,
     nsMediaFeature::eBoolInteger,
     nsMediaFeature::eUserAgentAndChromeOnly,
--- a/layout/style/test/test_media_queries.html
+++ b/layout/style/test/test_media_queries.html
@@ -787,16 +787,19 @@ function run() {
   should_not_apply("(-moz-is-glyph:0)");
   should_not_apply("not all and (-moz-is-glyph:1)");
   should_not_apply("only all and (-moz-is-glyph:0)");
   should_not_apply("(-moz-is-glyph)");
   should_not_apply("(-moz-is-glyph:1)");
   should_not_apply("not all and (-moz-is-glyph:0)");
   should_not_apply("only all and (-moz-is-glyph:1)");
 
+  // Resource documents (UA-only).
+  query_should_not_be_parseable("(-moz-is-resource-document)");
+
   // Parsing tests
   // bug 454227
   should_apply_unbalanced("(orientation");
   should_not_apply_unbalanced("not all and (orientation");
   should_not_apply_unbalanced("(orientation:");
   should_apply_unbalanced("all,(orientation:");
   should_not_apply_unbalanced("(orientation:,all");
   should_apply_unbalanced("not all and (grid");
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -74,16 +74,17 @@
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsIScriptError.h"
 #include "nsPrintfCString.h"
 #include "nsURLHelper.h"
 #include "nsNetUtil.h"
 #include "nsIURLParser.h"
 #include "NullPrincipal.h"
+#include "js/GCAnnotations.h"
 #include "mozilla/PeerIdentity.h"
 #include "mozilla/dom/RTCCertificate.h"
 #include "mozilla/dom/RTCConfigurationBinding.h"
 #include "mozilla/dom/RTCDTMFSenderBinding.h"
 #include "mozilla/dom/RTCDTMFToneChangeEvent.h"
 #include "mozilla/dom/RTCRtpReceiverBinding.h"
 #include "mozilla/dom/RTCRtpSenderBinding.h"
 #include "mozilla/dom/RTCStatsReportBinding.h"
@@ -150,17 +151,17 @@ namespace {
 class JSErrorResult :
     public binding_danger::TErrorResult<binding_danger::JustAssertCleanupPolicy>
 {
 public:
   ~JSErrorResult()
   {
     SuppressException();
   }
-};
+} JS_HAZ_ROOTED;
 
 // The WrapRunnable() macros copy passed-in args and passes them to the function
 // later on the other thread. ErrorResult cannot be passed like this because it
 // disallows copy-semantics.
 //
 // This WrappableJSErrorResult hack solves this by not actually copying the
 // ErrorResult, but creating a new one instead, which works because we don't
 // care about the result.
@@ -179,17 +180,17 @@ public:
     if (isCopy) {
       MOZ_ASSERT(NS_IsMainThread());
     }
   }
   operator ErrorResult &() { return *mRv; }
 private:
   mozilla::UniquePtr<JSErrorResult> mRv;
   bool isCopy;
-};
+} JS_HAZ_ROOTED;
 
 }
 
 static nsresult InitNSSInContent()
 {
   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
 
   if (!XRE_IsContentProcess()) {
--- a/memory/build/mozjemalloc.cpp
+++ b/memory/build/mozjemalloc.cpp
@@ -1640,19 +1640,23 @@ pages_map(void* aAddr, size_t aSize)
 static inline void
 pages_copy(void* dest, const void* src, size_t n)
 {
 
   MOZ_ASSERT((void*)((uintptr_t)dest & ~gPageSizeMask) == dest);
   MOZ_ASSERT(n >= VM_COPY_MIN);
   MOZ_ASSERT((void*)((uintptr_t)src & ~gPageSizeMask) == src);
 
-  vm_copy(
+  kern_return_t r = vm_copy(
     mach_task_self(), (vm_address_t)src, (vm_size_t)n, (vm_address_t)dest);
+  if (r != KERN_SUCCESS) {
+    MOZ_CRASH("vm_copy() failed");
+  }
 }
+
 #endif
 
 template<size_t Bits>
 bool
 AddressRadixTree<Bits>::Init()
 {
   mLock.Init();
   mRoot = (void**)base_calloc(1 << kBitsAtLevel1, sizeof(void*));
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -113,18 +113,17 @@ impl Device {
     /// Get the font size of the root element (for rem)
     pub fn root_font_size(&self) -> Au {
         self.used_root_font_size.store(true, Ordering::Relaxed);
         Au::new(self.root_font_size.load(Ordering::Relaxed) as i32)
     }
 
     /// Set the font size of the root element (for rem)
     pub fn set_root_font_size(&self, size: Au) {
-        self.root_font_size
-            .store(size.0 as isize, Ordering::Relaxed)
+        self.root_font_size.store(size.0 as isize, Ordering::Relaxed)
     }
 
     /// Sets the body text color for the "inherit color from body" quirk.
     ///
     /// <https://quirks.spec.whatwg.org/#the-tables-inherit-color-from-body-quirk>
     pub fn set_body_text_color(&self, color: RGBA) {
         self.body_text_color
             .store(convert_rgba_to_nscolor(&color) as usize, Ordering::Relaxed)
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1129,49 +1129,44 @@ pub extern "C" fn Servo_Element_IsDispla
 #[no_mangle]
 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: RawGeckoElementBorrowed) -> bool {
     let element = GeckoElement(element);
     let data = element.borrow_data()
                       .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
     data.flags.contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
 }
 
-#[no_mangle]
-pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetContentsStrong {
-    let global_style_data = &*GLOBAL_STYLE_DATA;
-    let origin = match mode {
+fn mode_to_origin(mode: SheetParsingMode) -> Origin {
+    match mode {
         SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
         SheetParsingMode::eUserSheetFeatures => Origin::User,
         SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
         SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
-    };
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyleSheetContentsStrong {
+    let global_style_data = &*GLOBAL_STYLE_DATA;
+    let origin = mode_to_origin(mode);
     let shared_lock = &global_style_data.shared_lock;
     Arc::new(
         StylesheetContents::from_str(
             "",
             unsafe { dummy_url_data() }.clone(),
             origin,
             shared_lock,
             /* loader = */ None,
             &NullReporter,
             QuirksMode::NoQuirks,
             0
         )
     ).into_strong()
 }
 
-fn mode_to_origin(mode: SheetParsingMode) -> Origin {
-    match mode {
-        SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
-        SheetParsingMode::eUserSheetFeatures => Origin::User,
-        SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
-        SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
-    }
-}
-
 /// Note: The load_data corresponds to this sheet, and is passed as the parent
 /// load data for child sheet loads. It may be null for certain cases where we
 /// know we won't have child loads.
 #[no_mangle]
 pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
     loader: *mut Loader,
     stylesheet: *mut DomStyleSheet,
     load_data: *mut SheetLoadData,
--- a/taskcluster/ci/build/android.yml
+++ b/taskcluster/ci/build/android.yml
@@ -39,16 +39,17 @@ android-api-16/debug:
         custom-build-variant-cfg: api-16-debug
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-x86/opt:
     description: "Android 4.2 x86 Opt"
     index:
         product: mobile
         job-name: android-x86-opt
     treeherder:
@@ -92,16 +93,17 @@ android-x86/opt:
         custom-build-variant-cfg: x86
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-x86-nightly/opt:
     description: "Android 4.2 x86 Nightly"
     attributes:
         nightly: true
     shipping-phase: promote
     shipping-product: fennec
@@ -151,16 +153,17 @@ android-x86-nightly/opt:
         custom-build-variant-cfg: x86
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-api-16/opt:
     description: "Android 4.0 api-16+ Opt"
     index:
         product: mobile
         job-name: android-api-16-opt
     treeherder:
@@ -199,16 +202,17 @@ android-api-16/opt:
         custom-build-variant-cfg: api-16
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-api-16-without-google-play-services/opt:
     description: "Android 4.0 api-16+ (without Google Play Services) Opt"
     index:
         product: mobile
         job-name: android-api-16-without-google-play-services-opt
     treeherder:
@@ -246,16 +250,17 @@ android-api-16-without-google-play-servi
         tooltool-downloads: internal
     run-on-projects: ['mozilla-central']
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-api-16-nightly/opt:
     description: "Android 4.0 api-16+ Nightly"
     attributes:
         nightly: true
     shipping-phase: promote
     shipping-product: fennec
@@ -300,16 +305,17 @@ android-api-16-nightly/opt:
         custom-build-variant-cfg: api-16
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-aarch64/opt:
     description: "Android 5.0 AArch64 Opt"
     index:
         product: mobile
         job-name: android-aarch64-opt
     treeherder:
@@ -348,16 +354,17 @@ android-aarch64/opt:
         custom-build-variant-cfg: aarch64
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
 
 android-aarch64-nightly/opt:
     description: "Android 5.0 AArch64 Nightly"
     attributes:
         nightly: true
     shipping-phase: promote
     shipping-product: fennec
@@ -402,9 +409,10 @@ android-aarch64-nightly/opt:
         custom-build-variant-cfg: aarch64
         tooltool-downloads: internal
     toolchains:
         - android-gradle-dependencies
         - android-ndk-linux
         - android-sdk-linux
         - linux64-clang
         - linux64-rust-android
+        - linux64-rust-size
         - linux64-sccache
--- a/taskcluster/ci/build/linux.yml
+++ b/taskcluster/ci/build/linux.yml
@@ -18,16 +18,17 @@ linux64/opt:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-plain/opt:
     description: "Linux64 Opt Plain"
     index:
         product: firefox
         job-name: linux64-plain-opt
     treeherder:
@@ -77,16 +78,17 @@ linux64-dmd/opt:
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     run-on-projects: []
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64/pgo:
     description: "Linux64 PGO"
     index:
         product: firefox
         job-name: linux64-pgo
     treeherder:
@@ -105,16 +107,17 @@ linux64/pgo:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-fuzzing/debug:
     description: "Linux64 Fuzzing Debug"
     index:
         product: firefox
         job-name: linux64-fuzzing-debug
     treeherder:
@@ -136,16 +139,17 @@ linux64-fuzzing/debug:
         custom-build-variant-cfg: fuzzing-debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-sccache
         - linux64-rust
+        - linux64-rust-size
 
 linux64/debug:
     description: "Linux64 Debug"
     index:
         product: firefox
         job-name: linux64-debug
     treeherder:
         platform: linux64/debug
@@ -164,16 +168,17 @@ linux64/debug:
         custom-build-variant-cfg: debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-sccache
         - linux64-rust
+        - linux64-rust-size
 
 linux64-plain/debug:
     description: "Linux64 Debug Plain"
     index:
         product: firefox
         job-name: linux64-plain-debug
     treeherder:
         platform: linux64/debug
@@ -226,16 +231,17 @@ linux64-devedition-nightly/opt:
         tooltool-downloads: public
         need-xvfb: true
         custom-build-variant-cfg: devedition
     run-on-projects: ['mozilla-beta']
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-base-toolchains/opt:
     description: "Linux64 base toolchains Opt"
     index:
         product: firefox
         job-name: linux64-base-toolchains-opt
     treeherder:
@@ -313,16 +319,17 @@ linux/opt:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux/debug:
     description: "Linux32 Debug"
     index:
         product: firefox
         job-name: linux-debug
     treeherder:
@@ -342,16 +349,17 @@ linux/debug:
         secrets: true
         custom-build-variant-cfg: debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux/pgo:
     description: "Linux32 PGO"
     index:
         product: firefox
         job-name: linux-pgo
     treeherder:
@@ -371,16 +379,17 @@ linux/pgo:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux-rusttests/opt:
     description: "Linux32 Rust tests Opt"
     index:
         product: firefox
         job-name: linux-rusttests-opt
     treeherder:
@@ -475,16 +484,17 @@ linux-devedition-nightly/opt:
         tooltool-downloads: public
         need-xvfb: true
         custom-build-variant-cfg: devedition
     run-on-projects: ['mozilla-beta']
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux-nightly/opt:
     description: "Linux32 Nightly"
     attributes:
         nightly: true
     shipping-phase: build
     shipping-product: firefox
@@ -509,16 +519,17 @@ linux-nightly/opt:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 
 linux64-asan/opt:
     description: "Linux64 Opt ASAN"
     index:
         product: firefox
         job-name: linux64-asan-opt
@@ -540,16 +551,17 @@ linux64-asan/opt:
         secrets: true
         custom-build-variant-cfg: asan-tc
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 
 linux64-asan-fuzzing/opt:
     description: "Linux64 Fuzzing Opt ASAN"
     index:
         product: firefox
         job-name: linux64-fuzzing-asan-opt
@@ -571,16 +583,17 @@ linux64-asan-fuzzing/opt:
         secrets: true
         custom-build-variant-cfg: fuzzing-asan-tc
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-asan-reporter-nightly/opt:
     description: "Linux64 Opt ASAN Reporter Nightly"
     attributes:
         nightly: true
     index:
         product: firefox
@@ -605,16 +618,17 @@ linux64-asan-reporter-nightly/opt:
         secrets: true
         custom-build-variant-cfg: asan-reporter-tc
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-asan/debug:
     description: "Linux64 Debug ASAN"
     index:
         product: firefox
         job-name: linux64-asan-debug
     treeherder:
@@ -635,16 +649,17 @@ linux64-asan/debug:
         secrets: true
         custom-build-variant-cfg: asan-tc-and-debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-lto/opt:
     description: "Linux64 Opt LTO"
     index:
         product: firefox
         job-name: linux64-lto-opt
     treeherder:
@@ -666,16 +681,17 @@ linux64-lto/opt:
         secrets: true
         custom-build-variant-cfg: lto-tc
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-lto/debug:
     description: "Linux64 Debug LTO"
     index:
         product: firefox
         job-name: linux64-lto-debug
     treeherder:
@@ -697,16 +713,17 @@ linux64-lto/debug:
         secrets: true
         custom-build-variant-cfg: lto-tc-and-debug
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-nightly/opt:
     description: "Linux64 Nightly"
     attributes:
         nightly: true
     shipping-phase: build
     shipping-product: firefox
@@ -730,16 +747,17 @@ linux64-nightly/opt:
         script: "mozharness/scripts/fx_desktop_build.py"
         secrets: true
         tooltool-downloads: public
         need-xvfb: true
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-noopt/debug:
     description: "Linux64 No-optimize Debug"
     index:
         product: firefox
         job-name: linux64-noopt-debug
     treeherder:
@@ -761,16 +779,17 @@ linux64-noopt/debug:
         tooltool-downloads: public
         keep-artifacts: false
         need-xvfb: true
     run-on-projects: ['trunk', 'try']
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
 
 linux64-rusttests/opt:
     description: "Linux64 Rust tests Opt"
     index:
         product: firefox
         job-name: linux64-rusttests-opt
     treeherder:
@@ -976,9 +995,10 @@ linux64-add-on-devel/opt:
         custom-build-variant-cfg: add-on-devel
         tooltool-downloads: public
         need-xvfb: true
     run-on-projects: ['mozilla-beta', 'mozilla-release', 'mozilla-esr45']
     toolchains:
         - linux64-clang
         - linux64-gcc
         - linux64-rust
+        - linux64-rust-size
         - linux64-sccache
--- a/taskcluster/ci/build/macosx.yml
+++ b/taskcluster/ci/build/macosx.yml
@@ -24,16 +24,17 @@ macosx64/debug:
         tooltool-downloads: internal
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64/opt:
     description: "MacOS X x64 Cross-compile"
     index:
         product: firefox
         job-name: macosx64-opt
     treeherder:
@@ -56,16 +57,17 @@ macosx64/opt:
         tooltool-downloads: internal
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-asan-fuzzing/opt:
     description: "MacOS X x64 Cross-compile Fuzzing ASAN"
     index:
         product: firefox
         job-name: macosx64-fuzzing-asan-opt
     treeherder:
@@ -89,16 +91,17 @@ macosx64-asan-fuzzing/opt:
         tooltool-downloads: internal
     toolchains:
         - linux64-cctools-port
         - linux64-clang-macosx-cross
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-dmd/opt:
     description: "MacOS X x64 DMD Cross-compile"
     index:
         product: firefox
         job-name: macosx64-dmd-opt
     treeherder:
@@ -124,16 +127,17 @@ macosx64-dmd/opt:
     run-on-projects: []
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-devedition-nightly/opt:
     description: "MacOS X Dev Edition x64 Nightly"
     attributes:
         nightly: true
     shipping-phase: build
     shipping-product: devedition
@@ -164,16 +168,17 @@ macosx64-devedition-nightly/opt:
     run-on-projects: ['mozilla-beta']
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-noopt/debug:
     description: "MacOS X x64 No-optimize Debug"
     index:
         product: firefox
         job-name: macosx64-noopt-debug
     treeherder:
@@ -199,16 +204,17 @@ macosx64-noopt/debug:
     run-on-projects: ['trunk', 'try']
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-add-on-devel/opt:
     description: "MacOS X x64 add-on-devel"
     index:
         product: firefox
         job-name: macosx64-add-on-devel
     treeherder:
@@ -233,16 +239,17 @@ macosx64-add-on-devel/opt:
     run-on-projects: ['mozilla-beta', 'mozilla-release', 'mozilla-esr45']
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-nightly/opt:
     description: "MacOS X x64 Cross-compile Nightly"
     attributes:
         nightly: true
     shipping-phase: build
     shipping-product: firefox
@@ -271,16 +278,17 @@ macosx64-nightly/opt:
         tooltool-downloads: internal
     toolchains:
         - linux64-cctools-port
         - linux64-clang
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
 
 macosx64-ccov/debug:
     description: "MacOS X x64 Cross-compile Code Coverage"
     index:
         product: firefox
         job-name: macosx64-ccov-debug
     treeherder:
@@ -305,9 +313,10 @@ macosx64-ccov/debug:
     run-on-projects: ['try']
     toolchains:
         - linux64-cctools-port
         - linux64-clang-macosx-cross
         - linux64-hfsplus
         - linux64-libdmg
         - linux64-llvm-dsymutil
         - linux64-rust-macos
+        - linux64-rust-size
         - linux64-sccache
--- a/taskcluster/ci/build/windows.yml
+++ b/taskcluster/ci/build/windows.yml
@@ -19,16 +19,17 @@ win32/debug:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/debug.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32/opt:
     description: "Win32 Opt"
     index:
         product: firefox
         job-name: win32-opt
     treeherder:
@@ -47,16 +48,17 @@ win32/opt:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/opt.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-dmd/opt:
     description: "Win32 DMD Opt"
     index:
         product: firefox
         job-name: win32-dmd-opt
     treeherder:
@@ -78,16 +80,17 @@ win32-dmd/opt:
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/opt.py
         extra-config:
             mozconfig_variant: 'opt-dmd'
     run-on-projects: []
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32/pgo:
     description: "Win32 Opt PGO"
     index:
         product: firefox
         job-name: win32-pgo
     treeherder:
@@ -106,16 +109,17 @@ win32/pgo:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/opt.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64/debug:
     description: "Win64 Debug"
     index:
         product: firefox
         job-name: win64-debug
     treeherder:
@@ -134,16 +138,17 @@ win64/debug:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/debug.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-plain/debug:
     description: "Win64 Debug Plain"
     index:
         product: firefox
         job-name: win64-plain-debug
     treeherder:
@@ -191,16 +196,17 @@ win64/opt:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/opt.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-plain/opt:
     description: "Win64 Opt Plain"
     index:
         product: firefox
         job-name: win64-plain-opt
     treeherder:
@@ -251,16 +257,17 @@ win64-dmd/opt:
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/opt.py
         extra-config:
             mozconfig_variant: 'opt-dmd'
     run-on-projects: []
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-nightly/opt:
     description: "Win32 Nightly"
     index:
         product: firefox
         job-name: win32-opt
         type: nightly
@@ -293,16 +300,17 @@ win32-nightly/opt:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/opt.py
             - taskcluster_nightly.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-nightly/opt:
     description: "Win64 Nightly"
     index:
         product: firefox
         job-name: win64-opt
         type: nightly
@@ -328,16 +336,17 @@ win64-nightly/opt:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/opt.py
             - taskcluster_nightly.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64/pgo:
     description: "Win64 Opt PGO"
     index:
         product: firefox
         job-name: win64-pgo
     treeherder:
@@ -356,16 +365,17 @@ win64/pgo:
         config:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/opt.py
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-add-on-devel/opt:
     description: "Windows32 add-on-devel"
     index:
         product: firefox
         job-name: win32-add-on-devel
     treeherder:
@@ -385,16 +395,17 @@ win32-add-on-devel/opt:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/addondevel.py
     run-on-projects: ['mozilla-beta', 'mozilla-release', 'mozilla-esr45']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-add-on-devel/opt:
     description: "Windows64 add-on-devel"
     index:
         product: firefox
         job-name: win64-add-on-devel
     treeherder:
@@ -414,16 +425,17 @@ win64-add-on-devel/opt:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/addondevel.py
     run-on-projects: ['mozilla-beta', 'mozilla-release', 'mozilla-esr45']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-noopt/debug:
     description: "Win64 No-optimize Debug"
     index:
         product: firefox
         job-name: win64-noopt-debug
     treeherder:
@@ -443,16 +455,17 @@ win64-noopt/debug:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/noopt_debug.py
     run-on-projects: ['trunk', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-noopt/debug:
     description: "Win32 No-optimize Debug"
     index:
         product: firefox
         job-name: win32-noopt-debug
     treeherder:
@@ -472,16 +485,17 @@ win32-noopt/debug:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/noopt_debug.py
     run-on-projects: ['trunk', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-rusttests/opt:
     description: "Win32 Opt Rust tests"
     index:
         product: firefox
         job-name: win32-rusttests-opt
     treeherder:
@@ -561,16 +575,17 @@ win64-ccov/debug:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/ccov_debug.py
     run-on-projects: ['mozilla-central', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-asan/debug:
     description: "Win64 Debug ASAN"
     index:
         product: firefox
         job-name: win64-asan-debug
     treeherder:
@@ -591,16 +606,17 @@ win64-asan/debug:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/asan_debug.py
     run-on-projects: ['trunk', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-asan/opt:
     description: "Win64 Opt ASAN"
     index:
         product: firefox
         job-name: win64-asan-opt
     treeherder:
@@ -621,16 +637,17 @@ win64-asan/opt:
             - builds/releng_base_firefox.py
             - builds/taskcluster_base_windows.py
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/asan_opt.py
     run-on-projects: ['trunk', 'try']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-devedition-nightly/opt:
     description: "Win32 Dev Edition Nightly"
     index:
         product: devedition
         job-name: win32-opt
         type: nightly
@@ -664,16 +681,17 @@ win32-devedition-nightly/opt:
             - builds/taskcluster_base_win32.py
             - builds/taskcluster_sub_win32/opt.py
             - taskcluster_nightly.py
         custom-build-variant-cfg: devedition
     run-on-projects: ['mozilla-beta']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win64-devedition-nightly/opt:
     description: "Win64 Dev Edition Nightly"
     index:
         product: devedition
         job-name: win64-opt
         type: nightly
@@ -700,16 +718,17 @@ win64-devedition-nightly/opt:
             - builds/taskcluster_base_win64.py
             - builds/taskcluster_sub_win64/opt.py
             - taskcluster_nightly.py
         custom-build-variant-cfg: devedition
     run-on-projects: ['mozilla-beta']
     toolchains:
         - win64-clang-cl
         - win64-rust
+        - win64-rust-size
         - win64-sccache
 
 win32-mingw32/opt:
     description: "Win32 MinGW Opt"
     index:
         product: firefox
         job-name: win32-mingw32-opt
     treeherder:
--- a/taskcluster/ci/toolchain/linux.yml
+++ b/taskcluster/ci/toolchain/linux.yml
@@ -502,16 +502,35 @@ linux64-sccache:
         using: toolchain-script
         script: build-sccache.sh
         resources:
             - 'taskcluster/scripts/misc/tooltool-download.sh'
         toolchain-artifact: public/build/sccache2.tar.xz
     toolchains:
         - linux64-rust-1.24
 
+linux64-rust-size:
+    description: "rust-size toolchain build"
+    treeherder:
+        kind: build
+        platform: toolchains/opt
+        symbol: TL(rust-size)
+        tier: 1
+    worker-type: aws-provisioner-v1/gecko-{level}-b-linux
+    worker:
+        max-run-time: 1800
+    run:
+        using: toolchain-script
+        script: build-rust-size.sh
+        resources:
+            - 'taskcluster/scripts/misc/tooltool-download.sh'
+        toolchain-artifact: public/build/rust-size.tar.xz
+    toolchains:
+        - linux64-rust-1.24
+
 linux64-gn:
     description: "gn toolchain build"
     treeherder:
         kind: build
         platform: toolchains/opt
         symbol: TL(gn)
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-linux
--- a/taskcluster/ci/toolchain/windows.yml
+++ b/taskcluster/ci/toolchain/windows.yml
@@ -209,16 +209,37 @@ win64-sccache:
         using: toolchain-script
         script: build-sccache.sh
         resources:
             - 'taskcluster/scripts/misc/tooltool-download.sh'
         toolchain-artifact: public/build/sccache2.tar.bz2
     toolchains:
         - win64-rust-1.24
 
+win64-rust-size:
+    description: "rust-size toolchain build"
+    treeherder:
+        kind: build
+        platform: toolchains/opt
+        symbol: TW64(rust-size)
+        tier: 1
+    worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
+    worker:
+        max-run-time: 1800
+        env:
+            TOOLTOOL_MANIFEST: "browser/config/tooltool-manifests/win64/sccache-build.manifest"
+    run:
+        using: toolchain-script
+        script: build-rust-size.sh
+        resources:
+            - 'taskcluster/scripts/misc/tooltool-download.sh'
+        toolchain-artifact: public/build/rust-size.tar.bz2
+    toolchains:
+        - win64-rust-1.24
+
 win32-gn:
     description: "gn toolchain build"
     treeherder:
         kind: build
         platform: toolchains/opt
         symbol: TW32(gn)
         tier: 1
     worker-type: aws-provisioner-v1/gecko-{level}-b-win2012
new file mode 100755
--- /dev/null
+++ b/taskcluster/scripts/misc/build-rust-size.sh
@@ -0,0 +1,57 @@
+#!/bin/bash
+set -x -e -v
+
+OWNER=luser
+PROJECT=rust-size
+PROJECT_REVISION=4a5d9148f50dc037dc230f10b8fc4e5ca00016aa
+
+# This script is for building rust-size
+case "$(uname -s)" in
+Linux)
+    WORKSPACE=$HOME/workspace
+    UPLOAD_DIR=$HOME/artifacts
+    COMPRESS_EXT=xz
+    ;;
+MINGW*)
+    WORKSPACE=$PWD
+    UPLOAD_DIR=$WORKSPACE/public/build
+    WIN_WORKSPACE="$(pwd -W)"
+    COMPRESS_EXT=bz2
+
+    export INCLUDE="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/include;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/ucrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/shared;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/um;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/Include/10.0.15063.0/winrt;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/include"
+
+    export LIB="$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/VC/atlmfc/lib/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/um/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/SDK/lib/10.0.15063.0/ucrt/x64;$WIN_WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/lib/amd64"
+
+    PATH="$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx64/x64:$WORKSPACE/build/src/vs2017_15.4.2/VC/bin/Hostx86/x86:$WORKSPACE/build/src/vs2017_15.4.2/SDK/bin/10.0.15063.0/x64:$WORKSPACE/build/src/vs2017_15.4.2/redist/x64/Microsoft.VC141.CRT:$WORKSPACE/build/src/vs2017_15.4.2/SDK/Redist/ucrt/DLLs/x64:$WORKSPACE/build/src/vs2017_15.4.2/DIA SDK/bin/amd64:$WORKSPACE/build/src/mingw64/bin:$PATH"
+    ;;
+esac
+
+cd $WORKSPACE/build/src
+
+. taskcluster/scripts/misc/tooltool-download.sh
+
+# cargo gets mad if the parent directory has a Cargo.toml file in it
+if [ -e Cargo.toml ]; then
+  mv Cargo.toml Cargo.toml.back
+fi
+
+PATH="$PWD/rustc/bin:$PATH"
+
+git clone -n https://github.com/${OWNER}/${PROJECT} ${PROJECT}
+
+cd $PROJECT
+
+git checkout $PROJECT_REVISION
+
+cargo build --verbose --release
+
+mkdir $PROJECT
+cp target/release/${PROJECT}* ${PROJECT}/
+tar -acf ${PROJECT}.tar.$COMPRESS_EXT $PROJECT
+mkdir -p $UPLOAD_DIR
+cp ${PROJECT}.tar.$COMPRESS_EXT $UPLOAD_DIR
+
+cd ..
+if [ -e Cargo.toml.back ]; then
+  mv Cargo.toml.back Cargo.toml
+fi
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1601,77 +1601,93 @@ or run without that action (ie: --no-{ac
             })
 
     def _get_sections(self, file, filter=None):
         """
         Returns a dictionary of sections and their sizes.
         """
         from StringIO import StringIO
 
-        # Check for binutils' `size` program
-        size_names = ('size', 'gsize')
-        size_prog = None
-        for name in size_names:
-            size_prog = self.which(name)
-            if size_prog:
-                break
+        # Check for `rust_size`, our cross platform version of size. It should
+        # be installed by tooltool in $abs_src_dir/rust-size/rust-size
+        rust_size = os.path.join(self.query_abs_dirs()['abs_src_dir'],
+                                 'rust-size', 'rust-size')
+        size_prog = self.which(rust_size)
+        if not size_prog:
+            self.info("Couldn't find `rust-size` program")
+            return {}
 
-        if not size_prog:
-            self.info("Couldn't find `size` program")
+        self.info("Using %s" % size_prog)
+        cmd = [size_prog, file]
+        output = self.get_output_from_command(cmd)
+        if not output:
+            self.info("`rust-size` failed")
             return {}
 
-        # Call `size` and output with SysV format in decimal radix
-        cmd = [size_prog, '-A', '-d', file]
-        output = self.get_output_from_command(cmd)
-        if not output:
+        # Format is JSON:
+        # {
+        #   "section_type": {
+        #     "section_name": size, ....
+        #   },
+        #   ...
+        # }
+        try:
+            parsed = json.loads(output)
+        except ValueError:
+            self.info("`rust-size` failed: %s" % output)
             return {}
 
-        # Format is:
-        # <section-name> <size> <address>, ie:
-        # .data                  302160   101053344
-        size_section_re = re.compile(r"([\w\.]+)\s+(\d+)\s+(\d+)")
         sections = {}
-        for line in output.splitlines():
-            m = size_section_re.match(line)
-            if m:
-                name = m.group(1)
+        for sec_type in parsed.itervalues():
+            for name, size in sec_type.iteritems():
                 if not filter or name in filter:
-                    sections[name] = int(m.group(2))
+                    sections[name] = size
 
         return sections
 
     def _get_binary_metrics(self):
         """
         Provides metrics on interesting compenents of the built binaries.
         Currently just the sizes of interesting sections.
         """
         lib_interests = {
             'XUL': ('libxul.so', 'xul.dll', 'XUL'),
             'NSS': ('libnss3.so', 'nss3.dll', 'libnss3.dylib'),
             'NSPR': ('libnspr4.so', 'nspr4.dll', 'libnspr4.dylib'),
             'avcodec': ('libmozavcodec.so', 'mozavcodec.dll', 'libmozavcodec.dylib'),
             'avutil': ('libmozavutil.so', 'mozavutil.dll', 'libmozavutil.dylib')
         }
-        # TODO(erahm): update for windows and osx. As-is we only have support
-        # for `size` on debian which gives us linux and android.
-        section_interests = ('.text', '.data', '.rodata', '.data.rel.ro', '.bss')
+        section_interests = ('.text', '.data', '.rodata', '.rdata',
+                             '.cstring', '.data.rel.ro', '.bss')
         lib_details = []
 
         dirs = self.query_abs_dirs()
         dist_dir = os.path.join(dirs['abs_obj_dir'], 'dist')
         bin_dir = os.path.join(dist_dir, 'bin')
 
         for lib_type, lib_names in lib_interests.iteritems():
             for lib_name in lib_names:
                 lib = os.path.join(bin_dir, lib_name)
                 if os.path.exists(lib):
                     lib_size = 0
                     section_details = self._get_sections(lib, section_interests)
                     section_measurements = []
                     # Build up the subtests
+
+                    # Lump rodata sections together
+                    # - Mach-O separates out read-only string data as .cstring
+                    # - PE really uses .rdata, but XUL at least has a .rodata as well
+                    for ro_alias in ('.cstring', '.rdata'):
+                        if ro_alias in section_details:
+                            if '.rodata' in section_details:
+                                section_details['.rodata'] += section_details[ro_alias]
+                            else:
+                                section_details['.rodata'] = section_details[ro_alias]
+                            del section_details[ro_alias]
+
                     for k, v in section_details.iteritems():
                         section_measurements.append({'name': k, 'value': v})
                         lib_size += v
                     lib_details.append({
                         'name': lib_type,
                         'size': lib_size,
                         'sections': section_measurements
                     })