Merge m-c to m-i
authorPhil Ringnalda <philringnalda@gmail.com>
Fri, 02 Dec 2016 22:28:05 -0800
changeset 325160 1b2237e0b5e010ae3b182e4dbe79037635ee7997
parent 325139 237ba7e9c898fe41563b04afb2e4e16f1b96cf9a (current diff)
parent 325159 557548714db55136b51e1129d649e2599797985f (diff)
child 325161 bee6662585ed87109cb2ab1b05a16984025c95af
push id84610
push userphilringnalda@gmail.com
push dateSat, 03 Dec 2016 06:28:13 +0000
treeherdermozilla-inbound@1b2237e0b5e0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone53.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 m-c to m-i MozReview-Commit-ID: 5bYzmy6C41c
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -51,26 +51,35 @@ set_config('MOZ_CARGO_SUPPORTS_FROZEN', 
 @imports(_from='textwrap', _import='dedent')
 def rust_compiler(value, rustc, rustc_info):
     if value:
         if not rustc:
             die(dedent('''\
             Rust compiler not found.
             To compile rust language sources, you must have 'rustc' in your path.
             See https//www.rust-lang.org/ for more information.
+
+            You can install rust by running './mach bootstrap'
+            or by directly running the installer from https://rustup.rs/
             '''))
         version = rustc_info.version
-        min_version = Version('1.10')
+        min_version = Version('1.13')
         if version < min_version:
             die(dedent('''\
             Rust compiler {} is too old.
+
             To compile Rust language sources please install at least
             version {} of the 'rustc' toolchain and make sure it is
             first in your path.
+
             You can verify this by typing 'rustc --version'.
+
+            If you have the 'rustup' tool installed you can upgrade
+            to the latest release by typing 'rustup update'. The
+            installer is available from https://rustup.rs/
             '''.format(version, min_version)))
         return True
 
 set_config('MOZ_RUST', rust_compiler)
 
 @template
 def rust_triple_alias(host_or_target):
     """Template defining the alias used for rustc's --target flag.
--- a/config/config.mk
+++ b/config/config.mk
@@ -349,18 +349,16 @@ ifeq (,$(filter $(COLOR_CFLAGS:-f%=-fno-
 endif
 endef
 
 color_flags_vars := \
   COMPILE_CFLAGS \
   COMPILE_CXXFLAGS \
   COMPILE_CMFLAGS \
   COMPILE_CMMFLAGS \
-  HOST_CFLAGS \
-  HOST_CXXFLAGS \
   LDFLAGS \
   $(NULL)
 
 ifdef MACH_STDOUT_ISATTY
 ifdef COLOR_CFLAGS
 # TODO Bug 1319166 - iTerm2 interprets some bytes  sequences as a
 # request to show a print dialog. Don't enable color on iTerm2 until
 # a workaround is in place.
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -335,16 +335,30 @@ IsAnonymousFlexOrGridItem(const nsIFrame
 static inline bool
 IsFlexOrGridContainer(const nsIFrame* aFrame)
 {
   const nsIAtom* t = aFrame->GetType();
   return t == nsGkAtoms::flexContainerFrame ||
          t == nsGkAtoms::gridContainerFrame;
 }
 
+// Returns true IFF the given nsIFrame is a nsFlexContainerFrame and
+// represents a -webkit-{inline-}box container. The frame's GetType() result is
+// passed as a separate argument, since in most cases, the caller will have
+// looked it up already, and we'd rather not make redundant calls to the
+// virtual GetType() method.
+static inline bool
+IsFlexContainerForLegacyBox(const nsIFrame* aFrame,
+                            const nsIAtom* aFrameType)
+{
+  MOZ_ASSERT(aFrame->GetType() == aFrameType, "wrong aFrameType was passed");
+  return aFrameType == nsGkAtoms::flexContainerFrame &&
+    aFrame->HasAnyStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
+}
+
 #if DEBUG
 static void
 AssertAnonymousFlexOrGridItemParent(const nsIFrame* aChild,
                                     const nsIFrame* aParent)
 {
   MOZ_ASSERT(IsAnonymousFlexOrGridItem(aChild),
              "expected an anonymous flex or grid item child frame");
   MOZ_ASSERT(aParent, "expected a parent frame");
@@ -9916,23 +9930,27 @@ nsCSSFrameConstructor::sPseudoParentData
 };
 
 void
 nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems(
   nsFrameConstructorState& aState,
   FrameConstructionItemList& aItems,
   nsIFrame* aParentFrame)
 {
-  if (aItems.IsEmpty() ||
-      !::IsFlexOrGridContainer(aParentFrame)) {
+  if (aItems.IsEmpty()) {
     return;
   }
-
-  const bool isWebkitBox = nsFlexContainerFrame::IsLegacyBox(aParentFrame);
-
+  const nsIAtom* parentType = aParentFrame->GetType();
+  if (parentType != nsGkAtoms::flexContainerFrame &&
+      parentType != nsGkAtoms::gridContainerFrame) {
+    return;
+  }
+
+  const bool isWebkitBox = IsFlexContainerForLegacyBox(aParentFrame,
+                                                       parentType);
   FCItemIterator iter(aItems);
   do {
     // Advance iter past children that don't want to be wrapped
     if (iter.SkipItemsThatDontNeedAnonFlexOrGridItem(aState, isWebkitBox)) {
       // Hit the end of the items without finding any remaining children that
       // need to be wrapped. We're finished!
       return;
     }
@@ -12214,22 +12232,24 @@ nsCSSFrameConstructor::WipeContainingBlo
     return true;
   }
 
   nsIFrame* nextSibling = ::GetInsertNextSibling(aFrame, aPrevSibling);
 
   // Situation #2 is a flex or grid container frame into which we're inserting
   // new inline non-replaced children, adjacent to an existing anonymous
   // flex or grid item.
-  if (::IsFlexOrGridContainer(aFrame)) {
+  nsIAtom* frameType = aFrame->GetType();
+  if (frameType == nsGkAtoms::flexContainerFrame ||
+      frameType == nsGkAtoms::gridContainerFrame) {
     FCItemIterator iter(aItems);
 
     // Check if we're adding to-be-wrapped content right *after* an existing
     // anonymous flex or grid item (which would need to absorb this content).
-    const bool isWebkitBox = nsFlexContainerFrame::IsLegacyBox(aFrame);
+    const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame, frameType);
     if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
         iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
       RecreateFramesForContent(aFrame->GetContent(), true,
                                REMOVE_FOR_RECONSTRUCTION, nullptr);
       return true;
     }
 
     // Check if we're adding to-be-wrapped content right *before* an existing
@@ -12259,17 +12279,18 @@ nsCSSFrameConstructor::WipeContainingBlo
     // _flex/grid container_ as its parent in the content tree.
     nsFrameConstructorSaveState floatSaveState;
     aState.PushFloatContainingBlock(nullptr, floatSaveState);
 
     FCItemIterator iter(aItems);
     // Skip over things that _do_ need an anonymous flex item, because
     // they're perfectly happy to go here -- they won't cause a reframe.
     nsIFrame* containerFrame = aFrame->GetParent();
-    const bool isWebkitBox = nsFlexContainerFrame::IsLegacyBox(containerFrame);
+    const bool isWebkitBox =
+      IsFlexContainerForLegacyBox(containerFrame, containerFrame->GetType());
     if (!iter.SkipItemsThatNeedAnonFlexOrGridItem(aState,
                                                   isWebkitBox)) {
       // We hit something that _doesn't_ need an anonymous flex item!
       // Rebuild the flex container to bust it out.
       RecreateFramesForContent(containerFrame->GetContent(), true,
                                REMOVE_FOR_RECONSTRUCTION, nullptr);
       return true;
     }
@@ -12283,17 +12304,16 @@ nsCSSFrameConstructor::WipeContainingBlo
   // spaces. It containes these two special cases apart from tables:
   // 1) There are effectively three types of white spaces in ruby frames
   //    we handle differently: leading/tailing/inter-level space,
   //    inter-base/inter-annotation space, and inter-segment space.
   //    These three types of spaces can be converted to each other when
   //    their sibling changes.
   // 2) The first effective child of a ruby frame must always be a ruby
   //    base container. It should be created or destroyed accordingly.
-  nsIAtom* frameType = aFrame->GetType();
   if (IsRubyPseudo(aFrame) ||
       frameType == nsGkAtoms::rubyFrame ||
       RubyUtils::IsRubyContainerBox(frameType)) {
     // We want to optimize it better, and avoid reframing as much as
     // possible. But given the cases above, and the fact that a ruby
     // usually won't be very large, it should be fine to reframe it.
     RecreateFramesForContent(aFrame->GetContent(), true,
                              REMOVE_FOR_RECONSTRUCTION, nullptr);
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -82,43 +82,26 @@ kAxisOrientationToSidesMap[eNumAxisOrien
 // Returns true iff the given nsStyleDisplay has display:-webkit-{inline-}-box.
 static inline bool
 IsDisplayValueLegacyBox(const nsStyleDisplay* aStyleDisp)
 {
   return aStyleDisp->mDisplay == mozilla::StyleDisplay::WebkitBox ||
     aStyleDisp->mDisplay == mozilla::StyleDisplay::WebkitInlineBox;
 }
 
-/* static */ bool
-nsFlexContainerFrame::IsLegacyBox(const nsIFrame* aFrame)
+// Returns true if aFlexContainer is the frame for an element with
+// "display:-webkit-box" or "display:-webkit-inline-box". aFlexContainer is
+// expected to be an instance of nsFlexContainerFrame (enforced with an assert);
+// otherwise, this function's state-bit-check here is bogus.
+static bool
+IsLegacyBox(const nsIFrame* aFlexContainer)
 {
-  nsStyleContext* styleContext = aFrame->StyleContext();
-  const nsStyleDisplay* styleDisp = styleContext->StyleDisplay();
-
-  // Trivial case: just check "display" directly.
-  bool isLegacyBox = IsDisplayValueLegacyBox(styleDisp);
-
-  // If this frame is for a scrollable element, then it will actually have
-  // "display:block", and its *parent* will have the real flex-flavored display
-  // value. So in that case, check the parent to find out if we're legacy.
-  if (!isLegacyBox && styleDisp->mDisplay == mozilla::StyleDisplay::Block) {
-    nsStyleContext* parentStyleContext = styleContext->GetParent();
-    NS_ASSERTION(parentStyleContext &&
-                 (styleContext->GetPseudo() == nsCSSAnonBoxes::buttonContent ||
-                  styleContext->GetPseudo() == nsCSSAnonBoxes::scrolledContent),
-                 "The only way a nsFlexContainerFrame can have 'display:block' "
-                 "should be if it's the inner part of a scrollable or button "
-                 "element");
-    isLegacyBox = IsDisplayValueLegacyBox(parentStyleContext->StyleDisplay());
-  }
-
-  NS_ASSERTION(!isLegacyBox ||
-               aFrame->GetType() == nsGkAtoms::flexContainerFrame,
-               "legacy box with unexpected frame type");
-  return isLegacyBox;
+  MOZ_ASSERT(aFlexContainer->GetType() == nsGkAtoms::flexContainerFrame,
+             "only flex containers may be passed to this function");
+  return aFlexContainer->HasAnyStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
 }
 
 // Returns the "align-items" value that's equivalent to the legacy "box-align"
 // value in the given style struct.
 static uint8_t
 ConvertLegacyStyleToAlignItems(const nsStyleXUL* aStyleXUL)
 {
   // -[moz|webkit]-box-align corresponds to modern "align-items"
@@ -1126,17 +1109,17 @@ IsOrderLEQWithDOMFallback(nsIFrame* aFra
   if (aFrame1->GetType() == nsGkAtoms::placeholderFrame ||
       aFrame2->GetType() == nsGkAtoms::placeholderFrame) {
     // Treat placeholders (for abspos/fixedpos frames) as LEQ everything.  This
     // ensures we don't reorder them w.r.t. one another, which is sufficient to
     // prevent them from noticeably participating in "order" reordering.
     return true;
   }
 
-  bool isInLegacyBox = nsFlexContainerFrame::IsLegacyBox(aFrame1->GetParent());
+  const bool isInLegacyBox = IsLegacyBox(aFrame1->GetParent());
 
   int32_t order1 = GetOrderOrBoxOrdinalGroup(aFrame1, isInLegacyBox);
   int32_t order2 = GetOrderOrBoxOrdinalGroup(aFrame2, isInLegacyBox);
 
   if (order1 != order2) {
     return order1 < order2;
   }
 
@@ -1204,17 +1187,17 @@ IsOrderLEQ(nsIFrame* aFrame1,
   if (aFrame1->GetType() == nsGkAtoms::placeholderFrame ||
       aFrame2->GetType() == nsGkAtoms::placeholderFrame) {
     // Treat placeholders (for abspos/fixedpos frames) as LEQ everything.  This
     // ensures we don't reorder them w.r.t. one another, which is sufficient to
     // prevent them from noticeably participating in "order" reordering.
     return true;
   }
 
-  bool isInLegacyBox = nsFlexContainerFrame::IsLegacyBox(aFrame1->GetParent());
+  const bool isInLegacyBox = IsLegacyBox(aFrame1->GetParent());
 
   int32_t order1 = GetOrderOrBoxOrdinalGroup(aFrame1, isInLegacyBox);
   int32_t order2 = GetOrderOrBoxOrdinalGroup(aFrame2, isInLegacyBox);
 
   return order1 <= order2;
 }
 
 uint8_t
@@ -2269,16 +2252,50 @@ NS_NewFlexContainerFrame(nsIPresShell* a
 // nsFlexContainerFrame Method Implementations
 // ===========================================
 
 /* virtual */
 nsFlexContainerFrame::~nsFlexContainerFrame()
 {
 }
 
+/* virtual */
+void
+nsFlexContainerFrame::Init(nsIContent*       aContent,
+                           nsContainerFrame* aParent,
+                           nsIFrame*         aPrevInFlow)
+{
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
+
+  const nsStyleDisplay* styleDisp = StyleContext()->StyleDisplay();
+
+  // Figure out if we should set a frame state bit to indicate that this frame
+  // represents a legacy -webkit-{inline-}box container.
+  // First, the trivial case: just check "display" directly.
+  bool isLegacyBox = IsDisplayValueLegacyBox(styleDisp);
+
+  // If this frame is for a scrollable element, then it will actually have
+  // "display:block", and its *parent* will have the real flex-flavored display
+  // value. So in that case, check the parent to find out if we're legacy.
+  if (!isLegacyBox && styleDisp->mDisplay == mozilla::StyleDisplay::Block) {
+    nsStyleContext* parentStyleContext = mStyleContext->GetParent();
+    NS_ASSERTION(parentStyleContext &&
+                 (mStyleContext->GetPseudo() == nsCSSAnonBoxes::buttonContent ||
+                  mStyleContext->GetPseudo() == nsCSSAnonBoxes::scrolledContent),
+                 "The only way a nsFlexContainerFrame can have 'display:block' "
+                 "should be if it's the inner part of a scrollable or button "
+                 "element");
+    isLegacyBox = IsDisplayValueLegacyBox(parentStyleContext->StyleDisplay());
+  }
+
+  if (isLegacyBox) {
+    AddStateBits(NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX);
+  }
+}
+
 template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
 /* static */ bool
 nsFlexContainerFrame::SortChildrenIfNeeded()
 {
   if (nsIFrame::IsFrameListSorted<IsLessThanOrEqual>(mFrames)) {
     return false;
   }
 
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -53,16 +53,20 @@ public:
 
   // Forward-decls of helper classes
   class FlexItem;
   class FlexLine;
   class FlexboxAxisTracker;
   struct StrutInfo;
 
   // nsIFrame overrides
+  void Init(nsIContent*       aContent,
+            nsContainerFrame* aParent,
+            nsIFrame*         aPrevInFlow) override;
+
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsRect&           aDirtyRect,
                                 const nsDisplayListSet& aLists) override;
 
   virtual void Reflow(nsPresContext*           aPresContext,
                       ReflowOutput&     aDesiredSize,
                       const ReflowInput& aReflowInput,
                       nsReflowStatus&          aStatus) override;
@@ -102,22 +106,16 @@ public:
     *                                     space to be divided up.
     */
   static void CalculatePackingSpace(uint32_t aNumThingsToPack,
                                     uint8_t aAlignVal,
                                     nscoord* aFirstSubjectOffset,
                                     uint32_t* aNumPackingSpacesRemaining,
                                     nscoord* aPackingSpaceRemaining);
 
-  /**
-   * Returns true if aFrame is the frame for an element with
-   * "display:-webkit-box" or "display:-webkit-inline-box".
-   */
-  static bool IsLegacyBox(const nsIFrame* aFrame);
-
 protected:
   // Protected constructor & destructor
   explicit nsFlexContainerFrame(nsStyleContext* aContext)
     : nsContainerFrame(aContext)
     , mBaselineFromLastReflow(NS_INTRINSIC_WIDTH_UNKNOWN)
   {}
   virtual ~nsFlexContainerFrame();
 
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -302,16 +302,20 @@ FRAME_STATE_BIT(Box, 61, NS_FRAME_MOUSE_
 // == Frame state bits that apply to flex container frames ====================
 
 FRAME_STATE_GROUP(FlexContainer, nsFlexContainerFrame)
 
 // Set for a flex container whose children have been reordered due to 'order'.
 // (Means that we have to be more thorough about checking them for sortedness.)
 FRAME_STATE_BIT(FlexContainer, 20, NS_STATE_FLEX_CHILDREN_REORDERED)
 
+// Set for a flex container that is emulating a legacy
+// 'display:-webkit-{inline-}box' container.
+FRAME_STATE_BIT(FlexContainer, 21, NS_STATE_FLEX_IS_LEGACY_WEBKIT_BOX)
+
 // == Frame state bits that apply to grid container frames ====================
 
 FRAME_STATE_GROUP(GridContainer, nsGridContainerFrame)
 
 // True iff the normal flow children are already in CSS 'order' in the
 // order they occur in the child frame list.
 FRAME_STATE_BIT(GridContainer, 20, NS_STATE_GRID_NORMAL_FLOW_CHILDREN_IN_CSS_ORDER)
 
--- a/layout/style/CSSLexer.h
+++ b/layout/style/CSSLexer.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef CSSLexer_h___
 #define CSSLexer_h___
 
 #include "mozilla/UniquePtr.h"
 #include "nsCSSScanner.h"
 #include "mozilla/dom/CSSLexerBinding.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
 
 namespace mozilla {
 namespace dom {
 
 class CSSLexer : public NonRefcountedDOMObject
 {
 public:
   explicit CSSLexer(const nsAString&);
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/css/ImportRule.h"
 #include "nsCSSRules.h"
 #include "nsIMediaList.h"
 #include "nsIDocument.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "nsQueryObject.h"
 #include "nsString.h"
+#include "nsStyleSet.h"
 #include "nsTArray.h"
 #include "nsIDOMCSSStyleSheet.h"
 #include "mozilla/dom/CSSRuleList.h"
 #include "nsIDOMMediaList.h"
 #include "nsIDOMNode.h"
 #include "nsError.h"
 #include "nsCSSParser.h"
 #include "mozilla/css/Loader.h"
--- a/layout/style/Declaration.cpp
+++ b/layout/style/Declaration.cpp
@@ -7,16 +7,17 @@
  * representation of a declaration block (or style attribute) in a CSS
  * stylesheet
  */
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "mozilla/css/Declaration.h"
+#include "mozilla/css/Rule.h"
 #include "nsPrintfCString.h"
 #include "gfxFontConstants.h"
 #include "nsStyleUtil.h"
 
 namespace mozilla {
 namespace css {
 
 NS_IMPL_QUERY_INTERFACE(ImportantStyleData, nsIStyleRule)
--- a/layout/style/RuleProcessorCache.cpp
+++ b/layout/style/RuleProcessorCache.cpp
@@ -6,16 +6,17 @@
 
 /*
  * cache of re-usable nsCSSRuleProcessors for given sets of style sheets
  */
 
 #include "RuleProcessorCache.h"
 
 #include <algorithm>
+#include "mozilla/CSSStyleSheet.h"
 #include "nsCSSRuleProcessor.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(RuleProcessorCache, nsIMemoryReporter)
 
 MOZ_DEFINE_MALLOC_SIZE_OF(RuleProcessorCacheMallocSizeOf)
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -27,16 +27,17 @@
 #include "nsTArray.h"
 
 #include "mozilla/EventStates.h"
 #include "mozilla/ServoElementSnapshot.h"
 #include "mozilla/ServoRestyleManager.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/dom/ElementInlines.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 #define SERVO_ARC_TYPE(name_, type_) \
   already_AddRefed<type_>            \
   type_##Strong::Consume() {         \
     RefPtr<type_> result;            \
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -14,17 +14,17 @@
 
 namespace mozilla {
 
 class ServoStyleSheet;
 namespace css {
 class Rule;
 } // namespace css
 
-class ServoCSSRuleList final : public CSSRuleList
+class ServoCSSRuleList final : public dom::CSSRuleList
 {
 public:
   ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
                    already_AddRefed<ServoCssRules> aRawRules);
 
   ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
 
   nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
--- a/layout/style/ServoStyleRule.cpp
+++ b/layout/style/ServoStyleRule.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/. */
 
 /* representation of CSSStyleRule for stylo */
 
 #include "mozilla/ServoStyleRule.h"
 
+#include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoDeclarationBlock.h"
 
 #include "nsDOMClassInfoID.h"
 #include "mozAutoDocUpdate.h"
 
 namespace mozilla {
 
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -1,22 +1,26 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ServoStyleSheet.h"
+
+#include "mozilla/css/Rule.h"
 #include "mozilla/StyleBackendType.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/ServoCSSRuleList.h"
 #include "mozilla/dom/CSSRuleList.h"
 
 #include "mozAutoDocUpdate.h"
 
+using namespace mozilla::dom;
+
 namespace mozilla {
 
 ServoStyleSheet::ServoStyleSheet(css::SheetParsingMode aParsingMode,
                                  CORSMode aCORSMode,
                                  net::ReferrerPolicy aReferrerPolicy,
                                  const dom::SRIMetadata& aIntegrity)
   : StyleSheet(StyleBackendType::Servo, aParsingMode)
   , mSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
--- a/layout/style/nsCSSPseudoClasses.cpp
+++ b/layout/style/nsCSSPseudoClasses.cpp
@@ -3,16 +3,17 @@
  * 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/. */
 
 /* atom list for CSS pseudo-classes */
 
 #include "mozilla/ArrayUtils.h"
 
 #include "nsCSSPseudoClasses.h"
+#include "nsCSSPseudoElements.h"
 #include "nsStaticAtom.h"
 #include "mozilla/Preferences.h"
 #include "nsString.h"
 
 using namespace mozilla;
 
 // define storage for all atoms
 #define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
--- a/layout/style/nsCSSPseudoClasses.h
+++ b/layout/style/nsCSSPseudoClasses.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* atom list for CSS pseudo-classes */
 
 #ifndef nsCSSPseudoClasses_h___
 #define nsCSSPseudoClasses_h___
 
 #include "nsStringFwd.h"
+#include "mozilla/CSSEnabledState.h"
 
 // The following two flags along with the pref defines where this pseudo
 // class can be used:
 // * If none of the two flags is presented, the pref completely controls
 //   the availability of this pseudo class. And in that case, if it has
 //   no pref, this property is usable everywhere.
 // * If any of the flags is set, this pseudo class is always enabled in
 //   the specific contexts regardless of the value of the pref. If there
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -9,16 +9,18 @@
 #include "nsCSSScanner.h"
 #include "nsStyleUtil.h"
 #include "nsISupportsImpl.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/css/ErrorReporter.h"
 #include "mozilla/Likely.h"
 #include <algorithm>
 
+using namespace mozilla;
+
 /* Character class tables and related helper functions. */
 
 static const uint8_t IS_HEX_DIGIT  = 0x01;
 static const uint8_t IS_IDSTART    = 0x02;
 static const uint8_t IS_IDCHAR     = 0x04;
 static const uint8_t IS_URL_CHAR   = 0x08;
 static const uint8_t IS_HSPACE     = 0x10;
 static const uint8_t IS_VSPACE     = 0x20;
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -23,16 +23,17 @@
 #include "nsNetUtil.h"
 #include "nsPresContext.h"
 #include "nsStyleUtil.h"
 #include "nsDeviceContext.h"
 #include "nsStyleSet.h"
 #include "nsContentUtils.h"
 
 using namespace mozilla;
+using namespace mozilla::css;
 
 static bool
 IsLocalRefURL(nsStringBuffer* aString)
 {
   // Find the first non-"C0 controls + space" character.
   char16_t* current = static_cast<char16_t*>(aString->Data());
   for (; *current != '\0'; current++) {
     if (*current > 0x20) {
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -4,17 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* DOM object for element.style */
 
 #include "nsDOMCSSAttrDeclaration.h"
 
 #include "mozilla/css/Declaration.h"
 #include "mozilla/css/StyleRule.h"
+#include "mozilla/DeclarationBlock.h"
+#include "mozilla/DeclarationBlockInlines.h"
 #include "mozilla/dom/Element.h"
+#include "mozilla/ServoDeclarationBlock.h"
 #include "nsIDocument.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIURI.h"
 #include "nsNodeUtils.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsIFrame.h"
 #include "ActiveLayerTracker.h"
 
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -14,16 +14,17 @@
 #include "nsCSSValue.h"
 #ifdef XP_WIN
 #include "mozilla/LookAndFeel.h"
 #endif
 #include "nsCSSRuleProcessor.h"
 #include "nsDeviceContext.h"
 #include "nsIBaseWindow.h"
 #include "nsIDocument.h"
+#include "nsIWidget.h"
 #include "nsContentUtils.h"
 #include "mozilla/StyleSheet.h"
 #include "mozilla/StyleSheetInlines.h"
 
 using namespace mozilla;
 
 static const nsCSSProps::KTableEntry kOrientationKeywords[] = {
   { eCSSKeyword_portrait,                 NS_STYLE_ORIENTATION_PORTRAIT },
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -6,17 +6,20 @@
 /* the interface (to internal code) for retrieving computed style data */
 
 #include "CSSVariableImageTable.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Maybe.h"
 
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
+#include "nsFontMetrics.h"
 #include "nsStyleConsts.h"
+#include "nsStyleStruct.h"
+#include "nsStyleStructInlines.h"
 #include "nsString.h"
 #include "nsPresContext.h"
 #include "nsIStyleRule.h"
 
 #include "nsCOMPtr.h"
 #include "nsStyleSet.h"
 #include "nsIPresShell.h"
 
--- a/layout/style/nsStyleCoord.cpp
+++ b/layout/style/nsStyleCoord.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* representation of length values in computed style data */
 
 #include "nsStyleCoord.h"
 #include "mozilla/HashFunctions.h"
 #include "mozilla/PodOperations.h"
 
+using namespace mozilla;
+
 nsStyleCoord::nsStyleCoord(nsStyleUnit aUnit)
   : mUnit(aUnit)
 {
   NS_ASSERTION(aUnit < eStyleUnit_Percent, "not a valueless unit");
   if (aUnit >= eStyleUnit_Percent) {
     mUnit = eStyleUnit_Null;
   }
   mValue.mInt = 0;
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -35,16 +35,17 @@
 #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
 #include "mozilla/dom/ImageTracker.h"
 #include "mozilla/Likely.h"
 #include "nsIURI.h"
 #include "nsIDocument.h"
 #include <algorithm>
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 static_assert((((1 << nsStyleStructID_Length) - 1) &
                ~(NS_STYLE_INHERIT_MASK)) == 0,
               "Not enough bits in NS_STYLE_INHERIT_MASK");
 
 /* static */ const int32_t nsStyleGridLine::kMinLine;
 /* static */ const int32_t nsStyleGridLine::kMaxLine;
 
--- a/taskcluster/ci/desktop-test/test-sets.yml
+++ b/taskcluster/ci/desktop-test/test-sets.yml
@@ -95,25 +95,25 @@ asan-tests:
     - xpcshell
 
 windows-vm-tests:
     - cppunit
     #- crashtest
     - external-media-tests
     #- gtest
     #- jittest
-    #- jsreftest
+    - jsreftest
     #- marionette
     #- mochitest
     #- mochitest-browser-chrome
-    #- mochitest-devtools-chrome
-    #- mochitest-jetpack
+    - mochitest-devtools-chrome
+    - mochitest-jetpack
     #- mochitest-media
     #- web-platform-tests
-    #- web-platform-tests-reftests
+    - web-platform-tests-reftests
     #- xpcshell
 
 # windows-gpu-tests:
 #    - reftest
 #    - reftest-no-accel
 #    - mochitest-webgl
 
 # these tests currently run on hardware, but may migrate above when validated
--- a/taskcluster/ci/desktop-test/tests.yml
+++ b/taskcluster/ci/desktop-test/tests.yml
@@ -152,16 +152,21 @@ jittest:
 jsreftest:
     description: "JS Reftest run"
     suite: reftest/jsreftest
     treeherder-symbol: tc-R(J)
     chunks:
         by-test-platform:
             win.*: 1
             default: 2
+    e10s:
+        by-test-platform:
+            # Bug 1321782
+            win.*: false
+            default: both
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 win.*:
                     - unittests/win_taskcluster_unittest.py
                 macosx.*:
@@ -384,16 +389,18 @@ mochitest-devtools-chrome:
             linux64-jsdcov/opt: []
             default: ['all']
     e10s:
         by-test-platform:
             # Bug 1242986: linux64/debug mochitest-devtools-chrome e10s is not greened up yet
             linux64/debug: false
             linux64-ccov/opt: false
             linux64-jsdcov/opt: false
+            # Bug 1304433: mochitest-devtools-chrome (e10s) not greened on windows
+            win.*: false
             default: both
     mozharness:
         script: desktop_unittest.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 win.*:
                     - unittests/win_taskcluster_unittest.py
@@ -661,16 +668,21 @@ web-platform-tests:
             - --test-type=testharness
 
 web-platform-tests-reftests:
     description: "Web platform reftest run"
     suite: web-platform-tests-reftests
     treeherder-symbol: tc-W(Wr)
     max-run-time: 5400
     instance-size: xlarge
+    e10s:
+        by-test-platform:
+            # Bug 1304438
+            win.*: false
+            default: both
     docker-image: {"in-tree": "desktop1604-test"}
     checkout: true
     mozharness:
         script: web_platform_tests.py
         no-read-buildbot-config: true
         config:
             by-test-platform:
                 win.*:
--- a/taskcluster/taskgraph/transforms/tests/all_kinds.py
+++ b/taskcluster/taskgraph/transforms/tests/all_kinds.py
@@ -42,16 +42,18 @@ def set_tier(config, tests):
     for test in tests:
         # only override if not set for the test
         if 'tier' not in test:
             if test['test-platform'] in ['linux64/debug',
                                          'linux64-asan/opt',
                                          'android-4.3-arm7-api-15/debug',
                                          'android-x86/opt']:
                 test['tier'] = 1
+            elif test['test-platform'].startswith('win'):
+                test['tier'] = 3
             else:
                 test['tier'] = 2
         yield test
 
 
 @transforms.add
 def set_expires_after(config, tests):
     """Try jobs expire after 2 weeks; everything else lasts 1 year.  This helps
@@ -86,16 +88,17 @@ def resolve_keyed_by(config, tests):
     """Resolve fields that can be keyed by platform, etc."""
     fields = [
         'instance-size',
         'max-run-time',
         'chunks',
         'e10s',
         'suite',
         'run-on-projects',
+        'tier',
     ]
     for test in tests:
         for field in fields:
             test[field] = get_keyed_by(item=test, field=field, item_name=test['test-name'])
         test['mozharness']['config'] = get_keyed_by(item=test,
                                                     field='mozharness',
                                                     subfield='config',
                                                     item_name=test['test-name'])
--- a/taskcluster/taskgraph/transforms/tests/test_description.py
+++ b/taskcluster/taskgraph/transforms/tests/test_description.py
@@ -61,17 +61,20 @@ test_description_schema = Schema({
     # projects on which this task should be included in the target task set.
     # See the attributes documentation for details.
     Optional('run-on-projects', default=['all']): Any(
         [basestring],
         {'by-test-platform': {basestring: [basestring]}},
     ),
 
     # the sheriffing tier for this task (default: set based on test platform)
-    Optional('tier'): int,
+    Optional('tier'): Any(
+        int,
+        {'by-test-platform': {basestring: int}},
+    ),
 
     # number of chunks to create for this task.  This can be keyed by test
     # platform by passing a dictionary in the `by-test-platform` key.  If the
     # test platform is not found, the key 'default' will be tried.
     Required('chunks', default=1): Any(
         int,
         {'by-test-platform': {basestring: int}},
     ),
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -565,16 +565,17 @@ class Marionette(object):
         :param app: Type of ``instance_class`` to use for managing app
             instance. See ``marionette_driver.geckoinstance``.
         :param instance_args: Arguments to pass to ``instance_class``.
 
         """
         self.host = host
         self.port = self.local_port = int(port)
         self.bin = bin
+        self.client = None
         self.instance = None
         self.session = None
         self.session_id = None
         self.process_id = None
         self.profile = None
         self.window = None
         self.chrome_window = None
         self.baseurl = baseurl
@@ -1303,17 +1304,19 @@ class Marionette(object):
                 self._send_message("deleteSession")
         finally:
             if reset_session_id:
                 self.session_id = None
             self.session = None
             self.process_id = None
             self.profile = None
             self.window = None
-            self.client.close()
+
+            if self.client is not None:
+                self.client.close()
 
     @property
     def session_capabilities(self):
         """A JSON dictionary representing the capabilities of the
         current session.
 
         """
         return self.session
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -2867,52 +2867,42 @@ GeckoDriver.prototype.commands = {
   "isElementEnabled": GeckoDriver.prototype.isElementEnabled,
   "isElementSelected": GeckoDriver.prototype.isElementSelected,
   "sendKeysToElement": GeckoDriver.prototype.sendKeysToElement,
   "clearElement": GeckoDriver.prototype.clearElement,
   "getTitle": GeckoDriver.prototype.getTitle,
   "getWindowType": GeckoDriver.prototype.getWindowType,
   "getPageSource": GeckoDriver.prototype.getPageSource,
   "get": GeckoDriver.prototype.get,
-  "goUrl": GeckoDriver.prototype.get,  // deprecated
   "getCurrentUrl": GeckoDriver.prototype.getCurrentUrl,
-  "getUrl": GeckoDriver.prototype.getCurrentUrl,  // deprecated
   "goBack": GeckoDriver.prototype.goBack,
   "goForward": GeckoDriver.prototype.goForward,
   "refresh":  GeckoDriver.prototype.refresh,
   "getWindowHandle": GeckoDriver.prototype.getWindowHandle,
-  "getCurrentWindowHandle":  GeckoDriver.prototype.getWindowHandle,  // Selenium 2 compat
   "getChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
   "getCurrentChromeWindowHandle": GeckoDriver.prototype.getChromeWindowHandle,
-  "getWindow":  GeckoDriver.prototype.getWindowHandle,  // deprecated
   "getWindowHandles": GeckoDriver.prototype.getWindowHandles,
   "getChromeWindowHandles": GeckoDriver.prototype.getChromeWindowHandles,
-  "getCurrentWindowHandles": GeckoDriver.prototype.getWindowHandles,  // Selenium 2 compat
-  "getWindows":  GeckoDriver.prototype.getWindowHandles,  // deprecated
   "getWindowPosition": GeckoDriver.prototype.getWindowPosition,
   "setWindowPosition": GeckoDriver.prototype.setWindowPosition,
   "getActiveFrame": GeckoDriver.prototype.getActiveFrame,
   "switchToFrame": GeckoDriver.prototype.switchToFrame,
   "switchToParentFrame": GeckoDriver.prototype.switchToParentFrame,
   "switchToWindow": GeckoDriver.prototype.switchToWindow,
   "switchToShadowRoot": GeckoDriver.prototype.switchToShadowRoot,
   "deleteSession": GeckoDriver.prototype.deleteSession,
   "importScript": GeckoDriver.prototype.importScript,
   "clearImportedScripts": GeckoDriver.prototype.clearImportedScripts,
   "getAppCacheStatus": GeckoDriver.prototype.getAppCacheStatus,
   "close": GeckoDriver.prototype.close,
-  "closeWindow": GeckoDriver.prototype.close,  // deprecated
   "closeChromeWindow": GeckoDriver.prototype.closeChromeWindow,
   "setTestName": GeckoDriver.prototype.setTestName,
   "takeScreenshot": GeckoDriver.prototype.takeScreenshot,
-  "screenShot": GeckoDriver.prototype.takeScreenshot,  // deprecated
-  "screenshot": GeckoDriver.prototype.takeScreenshot,  // Selenium 2 compat
   "addCookie": GeckoDriver.prototype.addCookie,
   "getCookies": GeckoDriver.prototype.getCookies,
-  "getAllCookies": GeckoDriver.prototype.getCookies,  // deprecated
   "deleteAllCookies": GeckoDriver.prototype.deleteAllCookies,
   "deleteCookie": GeckoDriver.prototype.deleteCookie,
   "getActiveElement": GeckoDriver.prototype.getActiveElement,
   "getScreenOrientation": GeckoDriver.prototype.getScreenOrientation,
   "setScreenOrientation": GeckoDriver.prototype.setScreenOrientation,
   "getWindowSize": GeckoDriver.prototype.getWindowSize,
   "setWindowSize": GeckoDriver.prototype.setWindowSize,
   "maximizeWindow": GeckoDriver.prototype.maximizeWindow,
--- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py
+++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_debug.py
@@ -11,16 +11,17 @@ config = {
     # - taskcluster_firefox_win32_opt
     # - taskcluster_firefox_win64_debug
     # - taskcluster_firefox_win64_opt
 
     'default_actions': [
         'clone-tools',
         'build',
         'check-test',
+        'generate-build-stats'
     ],
     'exes': {
         'python2.7': sys.executable,
         'make': [
             sys.executable,
             os.path.join(
                 os.getcwd(), 'build', 'src', 'build', 'pymake', 'make.py'
             )
--- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py
+++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_32_opt.py
@@ -11,16 +11,17 @@ config = {
     # - taskcluster_firefox_win32_opt
     # - taskcluster_firefox_win64_debug
     # - taskcluster_firefox_win64_opt
 
     'default_actions': [
         'clone-tools',
         'build',
         'check-test',
+        'generate-build-stats'
     ],
     'exes': {
         'python2.7': sys.executable,
         'make': [
             sys.executable,
             os.path.join(
                 os.getcwd(), 'build', 'src', 'build', 'pymake', 'make.py'
             )
--- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py
+++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_debug.py
@@ -11,16 +11,17 @@ config = {
     # - taskcluster_firefox_win32_opt
     # - taskcluster_firefox_win64_debug
     # - taskcluster_firefox_win64_opt
 
     'default_actions': [
         'clone-tools',
         'build',
         'check-test',
+        'generate-build-stats'
     ],
     'exes': {
         'python2.7': sys.executable,
         'make': [
             sys.executable,
             os.path.join(
                 os.getcwd(), 'build', 'src', 'build', 'pymake', 'make.py'
             )
--- a/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py
+++ b/testing/mozharness/configs/builds/taskcluster_firefox_windows_64_opt.py
@@ -11,16 +11,17 @@ config = {
     # - taskcluster_firefox_win32_opt
     # - taskcluster_firefox_win64_debug
     # - taskcluster_firefox_win64_opt
 
     'default_actions': [
         'clone-tools',
         'build',
         'check-test',
+        'generate-build-stats'
     ],
     'exes': {
         'python2.7': sys.executable,
         'make': [
             sys.executable,
             os.path.join(
                 os.getcwd(), 'build', 'src', 'build', 'pymake', 'make.py'
             )
--- a/testing/mozharness/mozharness/mozilla/building/buildbase.py
+++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py
@@ -1883,16 +1883,22 @@ or run without that action (ie: --no-{ac
                 continue
             data['subtests'].append({
                 'name': phase['name'],
                 'value': phase['duration'],
             })
 
         return data
 
+    def get_firefox_version(self):
+        versionFilePath = os.path.join(
+            self.query_abs_dirs()['abs_src_dir'], 'browser/config/version.txt')
+        with open(versionFilePath, 'r') as versionFile:
+            return versionFile.readline().strip()
+
     def generate_build_stats(self):
         """grab build stats following a compile.
 
         This action handles all statistics from a build: 'count_ctors'
         and then posts to graph server the results.
         We only post to graph server for non nightly build
         """
         if self.config.get('forced_artifact_build'):
@@ -1913,22 +1919,30 @@ or run without that action (ie: --no-{ac
 
         dirs = self.query_abs_dirs()
         packageName = self.query_buildbot_property('packageFilename')
 
         # if packageName is not set because we are not running in Buildbot,
         # then assume we are using MOZ_SIMPLE_PACKAGE_NAME, which means the
         # package is named one of target.{tar.bz2,zip,dmg}.
         if not packageName:
+            firefox_version = self.get_firefox_version()
             dist_dir = os.path.join(dirs['abs_obj_dir'], 'dist')
             for ext in ['apk', 'dmg', 'tar.bz2', 'zip']:
                 name = 'target.' + ext
                 if os.path.exists(os.path.join(dist_dir, name)):
                     packageName = name
                     break
+                # if we are not using MOZ_SIMPLE_PACKAGE_NAME, check for the
+                # default package naming convention
+                name = 'firefox-{}.en-US.{}.{}'.format(
+                    firefox_version, c.get('platform'), ext)
+                if os.path.exists(os.path.join(dist_dir, name)):
+                    packageName = name
+                    break
             else:
                 self.fatal("could not determine packageName")
 
         interests = ['libxul.so', 'classes.dex', 'omni.ja']
         installer = os.path.join(dirs['abs_obj_dir'], 'dist', packageName)
         installer_size = 0
         size_measurements = []
 
--- a/toolkit/components/extensions/ExtensionStorage.jsm
+++ b/toolkit/components/extensions/ExtensionStorage.jsm
@@ -13,17 +13,30 @@ const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OS",
                                   "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
                                   "resource://gre/modules/AsyncShutdown.jsm");
 
-function jsonReplacer(key, value) {
+/**
+ * Helper function used to sanitize the objects that have to be saved in the ExtensionStorage.
+ *
+ * @param {BaseContext} context
+ *   The current extension context.
+ * @param {string} key
+ *   The key of the current JSON property.
+ * @param {any} value
+ *   The value of the current JSON property.
+ *
+ * @returns {any}
+ *   The sanitized value of the property.
+ */
+function jsonReplacer(context, key, value) {
   switch (typeof(value)) {
     // Serialize primitive types as-is.
     case "string":
     case "number":
     case "boolean":
       return value;
 
     case "object":
@@ -44,17 +57,17 @@ function jsonReplacer(key, value) {
           return String(value);
       }
       break;
   }
 
   if (!key) {
     // If this is the root object, and we can't serialize it, serialize
     // the value to an empty object.
-    return {};
+    return new context.cloneScope.Object();
   }
 
   // Everything else, omit entirely.
   return undefined;
 }
 
 this.ExtensionStorage = {
   cache: new Map(),
@@ -67,17 +80,17 @@ this.ExtensionStorage = {
    * @param {value} value
    *        The value to sanitize.
    * @param {Context} context
    *        The extension context in which to sanitize the value
    * @returns {value}
    *        The sanitized value.
    */
   sanitize(value, context) {
-    let json = context.jsonStringify(value, jsonReplacer);
+    let json = context.jsonStringify(value, jsonReplacer.bind(null, context));
     return JSON.parse(json);
   },
 
   getExtensionDir(extensionId) {
     return OS.Path.join(this.extensionDir, extensionId);
   },
 
   getStorageFile(extensionId) {