Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Wed, 16 May 2018 00:54:22 +0300
changeset 418398 380cf87c1ee3966dd94499942b73085754dc4824
parent 418352 9260cc524bb54d9318075578488de8a6f40677eb (current diff)
parent 418397 12bfd7a50a79e0509aabf9e97b72013a93d747d4 (diff)
child 418415 0acb9d9da524201f2199be02f71fe23c577549ec
child 418450 2404129f5672b9a91ea006c3f51cf171833a3124
push id33999
push userdluca@mozilla.com
push dateTue, 15 May 2018 21:54:51 +0000
treeherdermozilla-central@380cf87c1ee3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone62.0a1
first release with
nightly linux32
380cf87c1ee3 / 62.0a1 / 20180515220059 / files
nightly linux64
380cf87c1ee3 / 62.0a1 / 20180515220059 / files
nightly mac
380cf87c1ee3 / 62.0a1 / 20180515220059 / files
nightly win32
380cf87c1ee3 / 62.0a1 / 20180515220059 / files
nightly win64
380cf87c1ee3 / 62.0a1 / 20180515220059 / 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 mozilla-inbound to mozilla-central. a=merge
config/faster/rules.mk
dom/base/nsIDOMClassInfo.h
dom/html/nsHTMLDocument.cpp
dom/html/nsHTMLDocument.h
dom/webidl/CSSPrimitiveValue.webidl
dom/webidl/CSSValue.webidl
dom/webidl/CSSValueList.webidl
dom/webidl/RGBColor.webidl
dom/webidl/Rect.webidl
editor/libeditor/HTMLAnonymousNodeEditor.cpp
js/xpconnect/src/qsObjectHelper.h
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/backend/tup.py
python/mozbuild/mozbuild/test/backend/test_recursivemake.py
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-025.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-026.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-028.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-029.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-031.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-032.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-033.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-034.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-035.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-036.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-372.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-373.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-375.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-376.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-378.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-379.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-380.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-381.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-382.xht.ini
testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-383.xht.ini
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,18 +28,18 @@ DIST_GARBAGE = config.cache config.log c
    config/autoconf.mk \
    mozilla-config.h \
    netwerk/necko-config.h xpcom/xpcom-config.h xpcom/xpcom-private.h \
    .mozconfig.mk
 
 ifndef MOZ_PROFILE_USE
 # Automation builds should always have a new buildid, but for the sake of not
 # re-linking libxul on every incremental build we do not enforce this for
-# developer builds.
-ifneq (,$(MOZ_AUTOMATION)$(MOZ_BUILD_DATE))
+# developer builds.  Tests always need a new buildid as well.
+ifneq (,$(MOZ_AUTOMATION)$(MOZ_BUILD_DATE)$(TEST_MOZBUILD))
 buildid.h source-repo.h: FORCE
 endif
 endif
 
 ifdef JS_STANDALONE
 configure_dir = $(topsrcdir)/js/src
 else
 configure_dir = $(topsrcdir)
@@ -104,17 +104,17 @@ include $(topsrcdir)/build/rebuild-backe
 
 Makefile: $(BUILD_BACKEND_FILES)
 	@$(TOUCH) $@
 
 default:: $(BUILD_BACKEND_FILES)
 endif
 
 install_manifests := \
-  $(addprefix dist/,branding idl include public private xpi-stage) \
+  $(addprefix dist/,branding include public private xpi-stage) \
   _tests \
   $(NULL)
 # Skip the dist/bin install manifest when using the hybrid
 # FasterMake/RecursiveMake backend. This is a hack until bug 1241744 moves
 # xpidl handling to FasterMake in that case, mechanically making the dist/bin
 # install manifest non-existent (non-existent manifests being skipped)
 ifeq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 install_manifests += dist/bin
@@ -135,22 +135,20 @@ install_manifest_depends += \
 endif
 endif
 
 .PHONY: install-manifests
 install-manifests: $(addprefix install-,$(install_manifests))
 
 # If we're using the hybrid FasterMake/RecursiveMake backend, we want
 # to recurse in the faster/ directory in parallel of install manifests.
-# But dist/idl needs to happen before (cf. dependencies in
-# config/faster/rules.mk)
 ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 install-manifests: faster
 .PHONY: faster
-faster: install-dist/idl
+faster:
 	$(MAKE) -C faster FASTER_RECURSIVE_MAKE=1
 endif
 
 .PHONY: $(addprefix install-,$(install_manifests))
 $(addprefix install-,$(install_manifests)): install-%: $(install_manifest_depends)
 ifneq (,$(filter FasterMake+RecursiveMake,$(BUILD_BACKENDS)))
 	@# If we're using the hybrid FasterMake/RecursiveMake backend, we want
 	@# to ensure the FasterMake end doesn't have install manifests for the
--- a/accessible/base/AccIterator.cpp
+++ b/accessible/base/AccIterator.cpp
@@ -377,17 +377,17 @@ ItemIterator::Next()
   return mAnchor ? (mAnchor = AccGroupInfo::NextItemTo(mAnchor)) : nullptr;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeItemIterator
 ////////////////////////////////////////////////////////////////////////////////
 
-XULTreeItemIterator::XULTreeItemIterator(XULTreeAccessible* aXULTree,
+XULTreeItemIterator::XULTreeItemIterator(const XULTreeAccessible* aXULTree,
                                          nsITreeView* aTreeView,
                                          int32_t aRowIdx) :
   mXULTree(aXULTree), mTreeView(aTreeView), mRowCount(-1),
   mContainerLevel(-1), mCurrRowIdx(aRowIdx + 1)
 {
   mTreeView->GetRowCount(&mRowCount);
   if (aRowIdx != -1)
     mTreeView->GetLevel(aRowIdx, &mContainerLevel);
--- a/accessible/base/AccIterator.h
+++ b/accessible/base/AccIterator.h
@@ -296,28 +296,28 @@ private:
 
 
 /**
  * Used to iterate through XUL tree items of the same level.
  */
 class XULTreeItemIterator : public AccIterable
 {
 public:
-  XULTreeItemIterator(XULTreeAccessible* aXULTree, nsITreeView* aTreeView,
+  XULTreeItemIterator(const XULTreeAccessible* aXULTree, nsITreeView* aTreeView,
                       int32_t aRowIdx);
   virtual ~XULTreeItemIterator() { }
 
   virtual Accessible* Next() override;
 
 private:
   XULTreeItemIterator() = delete;
   XULTreeItemIterator(const XULTreeItemIterator&) = delete;
   XULTreeItemIterator& operator = (const XULTreeItemIterator&) = delete;
 
-  XULTreeAccessible* mXULTree;
+  const XULTreeAccessible* mXULTree;
   nsITreeView* mTreeView;
   int32_t mRowCount;
   int32_t mContainerLevel;
   int32_t mCurrRowIdx;
 };
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/base/MarkupMap.h
+++ b/accessible/base/MarkupMap.h
@@ -322,17 +322,18 @@ MARKUPMAP(section,
 
 MARKUPMAP(summary,
           New_HTMLSummary,
           roles::SUMMARY)
 
 MARKUPMAP(
   table,
   [](Element* aElement, Accessible* aContext) -> Accessible* {
-     if (aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableType) {
+     if (aElement->GetPrimaryFrame() &&
+         aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableType) {
        return new ARIAGridAccessibleWrap(aElement, aContext->Document());
      }
      return nullptr;
   },
   0
 )
 
 MARKUPMAP(time,
@@ -385,22 +386,23 @@ MARKUPMAP(
      // CreateAccessibleByFrameType dual logic.
      Accessible* table = aContext->IsTable() ? aContext : nullptr;
      if (!table && aContext->Parent() && aContext->Parent()->IsTable()) {
         table = aContext->Parent();
      }
      if (table) {
         nsIContent* parentContent = aElement->GetParent();
         nsIFrame* parentFrame = parentContent->GetPrimaryFrame();
-        if (!parentFrame->IsTableWrapperFrame()) {
+        if (parentFrame && !parentFrame->IsTableWrapperFrame()) {
           parentContent = parentContent->GetParent();
           parentFrame = parentContent->GetPrimaryFrame();
           if (table->GetContent() == parentContent &&
-              (!parentFrame->IsTableWrapperFrame() ||
-               aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableRowType)) {
+              ((parentFrame && !parentFrame->IsTableWrapperFrame()) ||
+               (aElement->GetPrimaryFrame() &&
+                aElement->GetPrimaryFrame()->AccessibleType() != eHTMLTableRowType))) {
             return new ARIARowAccessible(aElement, aContext->Document());
           }
         }
       }
       return nullptr;
   },
   0
 )
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -1049,16 +1049,30 @@ nsAccessibilityService::CreateAccessible
     return nullptr;
 
   nsIContent* content = aNode->AsContent();
   nsIFrame* frame = content->GetPrimaryFrame();
 
   // Check frame and its visibility. Note, hidden frame allows visible
   // elements in subtree.
   if (!frame || !frame->StyleVisibility()->IsVisible()) {
+    // display:contents element doesn't have a frame, but retains the semantics.
+    // All its children are unaffected.
+    if (content->IsElement() && content->AsElement()->IsDisplayContents()) {
+      const HTMLMarkupMapInfo* markupMap =
+        mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
+      if (markupMap && markupMap->new_func) {
+        RefPtr<Accessible> newAcc =
+          markupMap->new_func(content->AsElement(), aContext);
+        document->BindToDocument(newAcc, aria::GetRoleMap(content->AsElement()));
+        return newAcc;
+      }
+      return nullptr;
+    }
+
     if (aIsSubtreeHidden && !frame)
       *aIsSubtreeHidden = true;
 
     return nullptr;
   }
 
   if (frame->GetContent() != content) {
     // Not the main content for this frame. This happens because <area>
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -319,18 +319,24 @@ Accessible::TranslateString(const nsStri
   if (NS_SUCCEEDED(rv))
     aStringOut.Assign(xsValue);
 }
 
 uint64_t
 Accessible::VisibilityState() const
 {
   nsIFrame* frame = GetFrame();
-  if (!frame)
+  if (!frame) {
+    // Element having display:contents is considered visible semantically,
+    // despite it doesn't have a visually visible box.
+    if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
+      return states::OFFSCREEN;
+    }
     return states::INVISIBLE;
+  }
 
   // Walk the parent frame chain to see if there's invisible parent or the frame
   // is in background tab.
   if (!frame->StyleVisibility()->IsVisible())
     return states::INVISIBLE;
 
   // Offscreen state if the document's visibility state is not visible.
   if (Document()->IsHidden())
@@ -1941,18 +1947,22 @@ Accessible::AppendTextTo(nsAString& aTex
                          uint32_t aLength)
 {
   // Return text representation of non-text accessible within hypertext
   // accessible. Text accessible overrides this method to return enclosed text.
   if (aStartOffset != 0 || aLength == 0)
     return;
 
   nsIFrame *frame = GetFrame();
-  if (!frame)
+  if (!frame) {
+    if (mContent->IsElement() && mContent->AsElement()->IsDisplayContents()) {
+      aText += kEmbeddedObjectChar;
+    }
     return;
+  }
 
   NS_ASSERTION(mParent,
                "Called on accessible unbound from tree. Result can be wrong.");
 
   if (frame->IsBrFrame()) {
     aText += kForcedNewLineChar;
   } else if (mParent && nsAccUtils::MustPrune(mParent)) {
     // Expose the embedded object accessible as imaginary embedded object
@@ -2559,17 +2569,17 @@ bool
 Accessible::AreItemsOperable() const
 {
   return HasOwnContent() &&
     mContent->IsElement() &&
     mContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant);
 }
 
 Accessible*
-Accessible::CurrentItem()
+Accessible::CurrentItem() const
 {
   // Check for aria-activedescendant, which changes which element has focus.
   // For activedescendant, the ARIA spec does not require that the user agent
   // checks whether pointed node is actually a DOM descendant of the element
   // with the aria-activedescendant attribute.
   nsAutoString id;
   if (HasOwnContent() &&
       mContent->IsElement() &&
@@ -2582,17 +2592,17 @@ Accessible::CurrentItem()
       if (document)
         return document->GetAccessible(activeDescendantElm);
     }
   }
   return nullptr;
 }
 
 void
-Accessible::SetCurrentItem(Accessible* aItem)
+Accessible::SetCurrentItem(const Accessible* aItem)
 {
   nsAtom* id = aItem->GetContent()->GetID();
   if (id) {
     nsAutoString idStr;
     id->ToString(idStr);
     mContent->AsElement()->SetAttr(kNameSpaceID_None,
                                    nsGkAtoms::aria_activedescendant,
                                    idStr,
--- a/accessible/generic/Accessible.h
+++ b/accessible/generic/Accessible.h
@@ -430,17 +430,17 @@ public:
   /**
    * Return index in parent accessible.
    */
   virtual int32_t IndexInParent() const;
 
   /**
    * Return true if accessible has children;
    */
-  bool HasChildren() { return !!GetChildAt(0); }
+  bool HasChildren() const { return !!GetChildAt(0); }
 
   /**
    * Return first/last/next/previous sibling of the accessible.
    */
   inline Accessible* NextSibling() const
     {  return GetSiblingAtOffset(1); }
   inline Accessible* PrevSibling() const
     { return GetSiblingAtOffset(-1); }
@@ -845,22 +845,22 @@ public:
    * can be activated.
    */
   virtual bool AreItemsOperable() const;
 
   /**
    * Return the current item of the widget, i.e. an item that has or will have
    * keyboard focus when widget gets active.
    */
-  virtual Accessible* CurrentItem();
+  virtual Accessible* CurrentItem() const;
 
   /**
    * Set the current item of the widget.
    */
-  virtual void SetCurrentItem(Accessible* aItem);
+  virtual void SetCurrentItem(const Accessible* aItem);
 
   /**
    * Return container widget this accessible belongs to.
    */
   virtual Accessible* ContainerWidget() const;
 
   /**
    * Return the localized string for the given key.
--- a/accessible/generic/RootAccessible.cpp
+++ b/accessible/generic/RootAccessible.cpp
@@ -97,17 +97,17 @@ RootAccessible::NativeRole() const
     return roles::DIALOG;
 
   return DocAccessibleWrap::NativeRole();
 }
 
 // RootAccessible protected member
 #ifdef MOZ_XUL
 uint32_t
-RootAccessible::GetChromeFlags()
+RootAccessible::GetChromeFlags() const
 {
   // Return the flag set for the top level window as defined
   // by nsIWebBrowserChrome::CHROME_WINDOW_[FLAGNAME]
   // Not simple: nsIXULWindow is not just a QI from nsIDOMWindow
   nsCOMPtr<nsIDocShell> docShell = nsCoreUtils::GetDocShellFor(mDocumentNode);
   NS_ENSURE_TRUE(docShell, 0);
   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
   docShell->GetTreeOwner(getter_AddRefs(treeOwner));
--- a/accessible/generic/RootAccessible.h
+++ b/accessible/generic/RootAccessible.h
@@ -71,17 +71,17 @@ protected:
   void HandlePopupHidingEvent(nsINode* aNode);
 
 #ifdef MOZ_XUL
   void HandleTreeRowCountChangedEvent(dom::Event* aEvent,
                                       XULTreeAccessible* aAccessible);
   void HandleTreeInvalidatedEvent(dom::Event* aEvent,
                                   XULTreeAccessible* aAccessible);
 
-    uint32_t GetChromeFlags();
+    uint32_t GetChromeFlags() const;
 #endif
 };
 
 inline RootAccessible*
 Accessible::AsRoot()
 {
   return IsRoot() ? static_cast<mozilla::a11y::RootAccessible*>(this) : nullptr;
 }
--- a/accessible/html/HTMLSelectAccessible.cpp
+++ b/accessible/html/HTMLSelectAccessible.cpp
@@ -88,32 +88,32 @@ HTMLSelectListAccessible::IsActiveWidget
 
 bool
 HTMLSelectListAccessible::AreItemsOperable() const
 {
   return true;
 }
 
 Accessible*
-HTMLSelectListAccessible::CurrentItem()
+HTMLSelectListAccessible::CurrentItem() const
 {
   nsIListControlFrame* listControlFrame = do_QueryFrame(GetFrame());
   if (listControlFrame) {
     nsCOMPtr<nsIContent> activeOptionNode = listControlFrame->GetCurrentOption();
     if (activeOptionNode) {
       DocAccessible* document = Document();
       if (document)
         return document->GetAccessible(activeOptionNode);
     }
   }
   return nullptr;
 }
 
 void
-HTMLSelectListAccessible::SetCurrentItem(Accessible* aItem)
+HTMLSelectListAccessible::SetCurrentItem(const Accessible* aItem)
 {
   if (!aItem->GetContent()->IsElement())
     return;
 
   aItem->GetContent()->AsElement()->SetAttr(kNameSpaceID_None,
                                             nsGkAtoms::selected,
                                             NS_LITERAL_STRING("true"),
                                             true);
@@ -495,23 +495,23 @@ HTMLComboboxAccessible::IsActiveWidget()
 bool
 HTMLComboboxAccessible::AreItemsOperable() const
 {
   nsIComboboxControlFrame* comboboxFrame = do_QueryFrame(GetFrame());
   return comboboxFrame && comboboxFrame->IsDroppedDown();
 }
 
 Accessible*
-HTMLComboboxAccessible::CurrentItem()
+HTMLComboboxAccessible::CurrentItem() const
 {
   return AreItemsOperable() ? mListAccessible->CurrentItem() : nullptr;
 }
 
 void
-HTMLComboboxAccessible::SetCurrentItem(Accessible* aItem)
+HTMLComboboxAccessible::SetCurrentItem(const Accessible* aItem)
 {
   if (AreItemsOperable())
     mListAccessible->SetCurrentItem(aItem);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLComboboxAccessible: protected
 
--- a/accessible/html/HTMLSelectAccessible.h
+++ b/accessible/html/HTMLSelectAccessible.h
@@ -44,18 +44,18 @@ public:
   // SelectAccessible
   virtual bool SelectAll() override;
   virtual bool UnselectAll() override;
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
-  virtual Accessible* CurrentItem() override;
-  virtual void SetCurrentItem(Accessible* aItem) override;
+  virtual Accessible* CurrentItem() const override;
+  virtual void SetCurrentItem(const Accessible* aItem) override;
 };
 
 /*
  * Options inside the select, contained within the list
  */
 class HTMLSelectOptionAccessible : public HyperTextAccessibleWrap
 {
 public:
@@ -175,18 +175,18 @@ public:
   virtual uint8_t ActionCount() override;
   virtual void ActionNameAt(uint8_t aIndex, nsAString& aName) override;
   virtual bool DoAction(uint8_t aIndex) override;
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
-  virtual Accessible* CurrentItem() override;
-  virtual void SetCurrentItem(Accessible* aItem) override;
+  virtual Accessible* CurrentItem() const override;
+  virtual void SetCurrentItem(const Accessible* aItem) override;
 
 protected:
   /**
    * Return selected option.
    */
   Accessible* SelectedOption() const;
 
 private:
--- a/accessible/tests/mochitest/states/test_visibility.html
+++ b/accessible/tests/mochitest/states/test_visibility.html
@@ -18,16 +18,17 @@
   <script type="application/javascript">
     // Tests
 
     function doTests() {
       testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
       testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
       testStates("div_transformed", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
       testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
+      testStates("ul", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 
@@ -61,11 +62,15 @@
       transformed!
     </div>
 
     <!-- edge case: no rect but has out of flow child -->
     <div id="div_abschild">
       <p style="position: absolute; left: 120px; top:120px;">absolute</p>
     </div>
 
+    <ul id="ul" style="display: contents;">
+      <li>Supermarket 1</li>
+      <li>Supermarket 2</li>
+    </ul>
   </div>
 </body>
 </html>
--- a/accessible/tests/mochitest/text/test_hypertext.html
+++ b/accessible/tests/mochitest/text/test_hypertext.html
@@ -34,17 +34,17 @@
       // ////////////////////////////////////////////////////////////////////////
       // hypertext
       // ////////////////////////////////////////////////////////////////////////
 
       // ! - embedded object char
       // __h__e__l__l__o__ __!__ __s__e__e__ __!__
       //  0  1  2  3  4  5  6  7  8  9 10 11 12 13
 
-      var IDs = [ "hypertext", "hypertext2" ];
+      var IDs = [ "hypertext", "hypertext2", "ht_displaycontents" ];
 
       // //////////////////////////////////////////////////////////////////////
       // characterCount
 
       testCharacterCount(IDs, 13);
 
       // //////////////////////////////////////////////////////////////////////
       // getText
@@ -118,16 +118,20 @@
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="nulltext"></div>
 
   <div id="hypertext">hello <a>friend</a> see <img src="about:blank"></div>
   <div id="hypertext2">hello <a>friend</a> see <input></div>
+  <div id="ht_displaycontents">hello <a>friend</a> see <ul id="ul" style="display: contents;">
+    <li>Supermarket 1</li>
+    <li>Supermarket 2</li>
+  </ul></div>
   <ol id="list">
     <li id="listitem">foo</li>
     <li id="listitemnone">bar</li>
   </ol>
 
   <div id="hypertext3">line
 <!-- haha -->
 <!-- hahaha -->
--- a/accessible/tests/mochitest/tree/a11y.ini
+++ b/accessible/tests/mochitest/tree/a11y.ini
@@ -20,16 +20,17 @@ skip-if = true # Bug 561508
 [test_aria_presentation.html]
 [test_aria_table.html]
 [test_brokencontext.html]
 [test_button.xul]
 [test_canvas.html]
 [test_combobox.xul]
 [test_cssflexbox.html]
 [test_cssoverflow.html]
+[test_display_contents.html]
 [test_dochierarchy.html]
 [test_dockids.html]
 [test_filectrl.html]
 [test_formctrl.html]
 skip-if = buildapp == "mulet"
 [test_formctrl.xul]
 [test_gencontent.html]
 [test_groupbox.xul]
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/tree/test_display_contents.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+<title>CSS display:contents tests</title>
+<link rel="stylesheet" type="text/css"
+      href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+<script type="application/javascript"
+        src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+
+<script type="application/javascript"
+        src="../common.js"></script>
+<script type="application/javascript"
+        src="../role.js"></script>
+
+<script type="application/javascript">
+function doTest() {
+  let tree =
+    { LIST: [
+      { LISTITEM: [
+        { STATICTEXT: [] },
+        { TEXT_LEAF: [] }
+      ]},
+      { LISTITEM: [
+        { STATICTEXT: [] },
+        { TEXT_LEAF: [] }
+      ]},
+    ] };
+  testAccessibleTree("ul", tree);
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addA11yLoadEvent(doTest);
+</script>
+</head>
+<body>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <ul id="ul" style="display: contents;">
+    <li>Supermarket 1</li>
+    <li>Supermarket 2</li>
+  </ul>
+</body>
+</html>
--- a/accessible/xul/XULMenuAccessible.cpp
+++ b/accessible/xul/XULMenuAccessible.cpp
@@ -568,26 +568,26 @@ XULMenubarAccessible::IsActiveWidget() c
 
 bool
 XULMenubarAccessible::AreItemsOperable() const
 {
   return true;
 }
 
 Accessible*
-XULMenubarAccessible::CurrentItem()
+XULMenubarAccessible::CurrentItem() const
 {
   nsMenuBarFrame* menuBarFrame = do_QueryFrame(GetFrame());
   if (menuBarFrame) {
     nsMenuFrame* menuFrame = menuBarFrame->GetCurrentMenuItem();
     if (menuFrame) {
       nsIContent* menuItemNode = menuFrame->GetContent();
       return mDoc->GetAccessible(menuItemNode);
     }
   }
   return nullptr;
 }
 
 void
-XULMenubarAccessible::SetCurrentItem(Accessible* aItem)
+XULMenubarAccessible::SetCurrentItem(const Accessible* aItem)
 {
   NS_ERROR("XULMenubarAccessible::SetCurrentItem not implemented");
 }
--- a/accessible/xul/XULMenuAccessible.h
+++ b/accessible/xul/XULMenuAccessible.h
@@ -103,18 +103,18 @@ public:
   XULMenubarAccessible(nsIContent* aContent, DocAccessible* aDoc);
 
   // Accessible
   virtual a11y::role NativeRole() const override;
 
   // Widget
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
-  virtual Accessible* CurrentItem() override;
-  virtual void SetCurrentItem(Accessible* aItem) override;
+  virtual Accessible* CurrentItem() const override;
+  virtual void SetCurrentItem(const Accessible* aItem) override;
 
 protected:
   // Accessible
   virtual ENameValueFlag NativeName(nsString& aName) override;
 };
 
 } // namespace a11y
 } // namespace mozilla
--- a/accessible/xul/XULSelectControlAccessible.cpp
+++ b/accessible/xul/XULSelectControlAccessible.cpp
@@ -206,17 +206,17 @@ XULSelectControlAccessible::SelectAll()
   // otherwise, don't support this method
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULSelectControlAccessible: Widgets
 
 Accessible*
-XULSelectControlAccessible::CurrentItem()
+XULSelectControlAccessible::CurrentItem() const
 {
   if (!mSelectControl)
     return nullptr;
 
   nsCOMPtr<nsIDOMXULSelectControlItemElement> currentItemElm;
   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
     do_QueryInterface(mSelectControl);
   if (multiSelectControl)
@@ -233,17 +233,17 @@ XULSelectControlAccessible::CurrentItem(
     if (document)
       return document->GetAccessible(DOMNode);
   }
 
   return nullptr;
 }
 
 void
-XULSelectControlAccessible::SetCurrentItem(Accessible* aItem)
+XULSelectControlAccessible::SetCurrentItem(const Accessible* aItem)
 {
   if (!mSelectControl)
     return;
 
   nsCOMPtr<nsIDOMXULSelectControlItemElement> itemElm =
     do_QueryInterface(aItem->GetContent());
   nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelectControl =
     do_QueryInterface(mSelectControl);
--- a/accessible/xul/XULSelectControlAccessible.h
+++ b/accessible/xul/XULSelectControlAccessible.h
@@ -31,18 +31,18 @@ public:
   virtual Accessible* GetSelectedItem(uint32_t aIndex) override;
   virtual bool IsItemSelected(uint32_t aIndex) override;
   virtual bool AddItemToSelection(uint32_t aIndex) override;
   virtual bool RemoveItemFromSelection(uint32_t aIndex) override;
   virtual bool SelectAll() override;
   virtual bool UnselectAll() override;
 
   // Widgets
-  virtual Accessible* CurrentItem() override;
-  virtual void SetCurrentItem(Accessible* aItem) override;
+  virtual Accessible* CurrentItem() const override;
+  virtual void SetCurrentItem(const Accessible* aItem) override;
 
 protected:
   // nsIDOMXULMultiSelectControlElement inherits from this, so we'll always have
   // one of these if the widget is valid and not defunct
   nsCOMPtr<nsIDOMXULSelectControlElement> mSelectControl;
 };
 
 } // namespace a11y
--- a/accessible/xul/XULTreeAccessible.cpp
+++ b/accessible/xul/XULTreeAccessible.cpp
@@ -217,17 +217,17 @@ XULTreeAccessible::ChildAtPoint(int32_t 
 
   return child;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // XULTreeAccessible: SelectAccessible
 
 Accessible*
-XULTreeAccessible::CurrentItem()
+XULTreeAccessible::CurrentItem() const
 {
   if (!mTreeView)
     return nullptr;
 
   nsCOMPtr<nsITreeSelection> selection;
   mTreeView->GetSelection(getter_AddRefs(selection));
   if (selection) {
     int32_t currentIndex = -1;
@@ -235,17 +235,17 @@ XULTreeAccessible::CurrentItem()
     if (currentIndex >= 0)
       return GetTreeItemAccessible(currentIndex);
   }
 
   return nullptr;
 }
 
 void
-XULTreeAccessible::SetCurrentItem(Accessible* aItem)
+XULTreeAccessible::SetCurrentItem(const Accessible* aItem)
 {
   NS_ERROR("XULTreeAccessible::SetCurrentItem not implemented");
 }
 
 void
 XULTreeAccessible::SelectedItems(nsTArray<Accessible*>* aItems)
 {
   if (!mTreeView)
--- a/accessible/xul/XULTreeAccessible.h
+++ b/accessible/xul/XULTreeAccessible.h
@@ -59,18 +59,18 @@ public:
   virtual bool RemoveItemFromSelection(uint32_t aIndex) override;
   virtual bool SelectAll() override;
   virtual bool UnselectAll() override;
 
   // Widgets
   virtual bool IsWidget() const override;
   virtual bool IsActiveWidget() const override;
   virtual bool AreItemsOperable() const override;
-  virtual Accessible* CurrentItem() override;
-  virtual void SetCurrentItem(Accessible* aItem) override;
+  virtual Accessible* CurrentItem() const override;
+  virtual void SetCurrentItem(const Accessible* aItem) override;
 
   virtual Accessible* ContainerWidget() const override;
 
   // XULTreeAccessible
 
   /**
    * Return tree item accessible at the givem row. If accessible doesn't exist
    * in the cache then create and cache it.
--- a/config/faster/rules.mk
+++ b/config/faster/rules.mk
@@ -92,24 +92,16 @@ ACDEFINES += -DBUILD_FASTER
 		-DBOOKMARKS_INCLUDE_DIR=$(TOPSRCDIR)/browser/locales/en-US/profile \
 		$(ACDEFINES) \
 		install_$(subst /,_,$*)
 
 # ============================================================================
 # Below is a set of additional dependencies and variables used to build things
 # that are not supported by data in moz.build.
 
-# The xpidl target in config/makefiles/xpidl requires the install manifest for
-# dist/idl to have been processed. When using the hybrid
-# FasterMake/RecursiveMake backend, this dependency is handled in the top-level
-# Makefile.
-ifndef FASTER_RECURSIVE_MAKE
-$(TOPOBJDIR)/config/makefiles/xpidl/xpidl: $(TOPOBJDIR)/install-dist_idl
-endif
-
 $(TOPOBJDIR)/build/application.ini: $(TOPOBJDIR)/buildid.h $(TOPOBJDIR)/source-repo.h
 
 # The manifest of allowed system add-ons should be re-built when using
 # "build faster".
 #
 # Note the dependency on install-dist/bin.  The form of this
 # dependency is critical: it's triggering the stem rule (install-%)
 # above to force the dist/bin manifest to be processed.  The more
--- a/config/makefiles/xpidl/Makefile.in
+++ b/config/makefiles/xpidl/Makefile.in
@@ -36,17 +36,18 @@ code_gen_deps := $(topsrcdir)/xpcom/refl
 
 # TODO we should use py_action, but that would require extra directories to be
 # in the virtualenv.
 %.xpt:
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) $(PLY_INCLUDE) -I$(topsrcdir)/xpcom/idl-parser -I$(DEPTH)/xpcom/idl-parser/xpidl \
 		$(process_py) --cache-dir $(DEPTH)/xpcom/idl-parser/xpidl --depsdir $(idl_deps_dir) \
 		--bindings-conf $(topsrcdir)/dom/bindings/Bindings.conf \
-		$(dist_idl_dir) $(dist_include_dir) $(dist_xpcrs_dir) $(@D) \
+		$(foreach dir,$(all_idl_dirs),-I $(dir)) \
+		$(dist_include_dir) $(dist_xpcrs_dir) $(@D) \
 		$(basename $(notdir $@)) $($(basename $(notdir $@))_deps)
 # When some IDL is added or removed, if the actual IDL file was already, or
 # still is, in the tree, simple dependencies can't detect that the XPT needs
 # to be rebuilt.
 # Add the current value of $($(xpidl_module)_deps) in the depend file, such that
 # we can later check if the value has changed since last build, which will
 # indicate whether IDLs were added or removed.
 # Note that removing previously built files is not covered.
@@ -70,17 +71,16 @@ endif
 $(generated_file): $(xpt_files) $(code_gen_py) $(code_gen_deps)
 	$(REPORT_BUILD)
 	$(PYTHON_PATH) $(PLY_INCLUDE) $(code_gen_py) $(generated_file) $(xpt_files)
 
 -include $(depends_files)
 
 define xpt_deps
 $(1): $(call mkdir_deps,$(dir $(1)))
-$(1): $(addsuffix .idl,$(addprefix $(dist_idl_dir)/,$($(basename $(notdir $(1)))_deps)))
 ifneq ($($(basename $(notdir $(1)))_deps),$($(basename $(notdir $(1)))_deps_built))
 $(1): FORCE
 endif
 endef
 
 $(foreach xpt,$(xpt_files),$(eval $(call xpt_deps,$(xpt))))
 
 .PHONY: xpidl
--- a/devtools/server/actors/object/previewers.js
+++ b/devtools/server/actors/object/previewers.js
@@ -541,17 +541,16 @@ previewers.Object = [
 
   function ArrayLike({obj, hooks}, grip, rawObj) {
     if (isWorker || !rawObj ||
         obj.class != "DOMStringList" &&
         obj.class != "DOMTokenList" &&
         obj.class != "CSSRuleList" &&
         obj.class != "MediaList" &&
         obj.class != "StyleSheetList" &&
-        obj.class != "CSSValueList" &&
         obj.class != "NamedNodeMap" &&
         obj.class != "FileList" &&
         obj.class != "NodeList") {
       return false;
     }
 
     if (typeof rawObj.length != "number") {
       return false;
--- a/dom/base/UseCounters.conf
+++ b/dom/base/UseCounters.conf
@@ -103,13 +103,14 @@ method console.table
 method console.trace
 method console.warn
 method console.dir
 method console.dirxml
 method console.group
 method console.groupCollapsed
 method console.groupEnd
 method console.time
+method console.timeLog
 method console.timeEnd
 method console.exception
 method console.timeStamp
 method console.profile
 method console.profileEnd
--- a/dom/base/WindowNamedPropertiesHandler.cpp
+++ b/dom/base/WindowNamedPropertiesHandler.cpp
@@ -108,52 +108,50 @@ WindowNamedPropertiesHandler::getOwnProp
   nsGlobalWindowInner* win = xpc::WindowOrNull(global);
   if (win->Length() > 0) {
     nsCOMPtr<nsPIDOMWindowOuter> childWin = win->GetChildWindow(str);
     if (childWin && ShouldExposeChildWindow(str, childWin)) {
       // We found a subframe of the right name. Shadowing via |var foo| in
       // global scope is still allowed, since |var| only looks up |own|
       // properties. But unqualified shadowing will fail, per-spec.
       JS::Rooted<JS::Value> v(aCx);
-      if (!WrapObject(aCx, childWin, &v)) {
+      if (!ToJSValue(aCx, nsGlobalWindowOuter::Cast(childWin), &v)) {
         return false;
       }
       FillPropertyDescriptor(aDesc, aProxy, 0, v);
       return true;
     }
   }
 
   // The rest of this function is for HTML documents only.
   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(win->GetExtantDoc());
   if (!htmlDoc) {
     return true;
   }
   nsHTMLDocument* document = static_cast<nsHTMLDocument*>(htmlDoc.get());
 
+  JS::Rooted<JS::Value> v(aCx);
   Element* element = document->GetElementById(str);
   if (element) {
-    JS::Rooted<JS::Value> v(aCx);
-    if (!WrapObject(aCx, element, &v)) {
+    if (!ToJSValue(aCx, element, &v)) {
       return false;
     }
     FillPropertyDescriptor(aDesc, aProxy, 0, v);
     return true;
   }
 
-  nsWrapperCache* cache;
-  nsISupports* result = document->ResolveName(str, &cache);
-  if (!result) {
-    return true;
+  ErrorResult rv;
+  bool found = document->ResolveName(aCx, str, &v, rv);
+  if (rv.MaybeSetPendingException(aCx)) {
+    return false;
   }
 
-  JS::Rooted<JS::Value> v(aCx);
-  if (!WrapObject(aCx, result, cache, nullptr, &v)) {
-    return false;
+  if (found) {
+    FillPropertyDescriptor(aDesc, aProxy, 0, v);
   }
-  FillPropertyDescriptor(aDesc, aProxy, 0, v);
   return true;
 }
 
 bool
 WindowNamedPropertiesHandler::defineProperty(JSContext* aCx,
                                              JS::Handle<JSObject*> aProxy,
                                              JS::Handle<jsid> aId,
                                              JS::Handle<JS::PropertyDescriptor> aDesc,
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -75,17 +75,16 @@ EXPORTS += [
     'nsIContent.h',
     'nsIContentInlines.h',
     'nsIContentIterator.h',
     'nsIContentSerializer.h',
     'nsIdentifierMapEntry.h',
     'nsIDocument.h',
     'nsIDocumentInlines.h',
     'nsIDocumentObserver.h',
-    'nsIDOMClassInfo.h',
     'nsIGlobalObject.h',
     'nsImageLoadingContent.h',
     'nsIMutationObserver.h',
     'nsINode.h',
     'nsINodeList.h',
     'nsIScriptContext.h',
     'nsIScriptGlobalObject.h',
     'nsIScriptObjectPrincipal.h',
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2843,19 +2843,17 @@ struct InterfaceShimEntry {
 
 // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
 // interface that has interface constants that sites might be getting off
 // of Ci.
 const InterfaceShimEntry kInterfaceShimMap[] =
 { { "nsIXMLHttpRequest", "XMLHttpRequest" },
   { "nsIDOMDOMException", "DOMException" },
   { "nsIDOMNode", "Node" },
-  { "nsIDOMCSSPrimitiveValue", "CSSPrimitiveValue" },
   { "nsIDOMCSSRule", "CSSRule" },
-  { "nsIDOMCSSValue", "CSSValue" },
   { "nsIDOMEvent", "Event" },
   { "nsIDOMNSEvent", "Event" },
   { "nsIDOMKeyEvent", "KeyEvent" },
   { "nsIDOMMouseEvent", "MouseEvent" },
   { "nsIDOMMouseScrollEvent", "MouseScrollEvent" },
   { "nsIDOMMutationEvent", "MutationEvent" },
   { "nsIDOMUIEvent", "UIEvent" },
   { "nsIDOMHTMLMediaElement", "HTMLMediaElement" },
deleted file mode 100644
--- a/dom/base/nsIDOMClassInfo.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- 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/. */
-
-#ifndef nsIDOMClassInfo_h___
-#define nsIDOMClassInfo_h___
-
-#include "nsIXPCScriptable.h"
-
-#define DOM_BASE_SCRIPTABLE_FLAGS                                          \
-  (XPC_SCRIPTABLE_USE_JSSTUB_FOR_ADDPROPERTY |                             \
-   XPC_SCRIPTABLE_USE_JSSTUB_FOR_DELPROPERTY |                             \
-   XPC_SCRIPTABLE_ALLOW_PROP_MODS_TO_PROTOTYPE |                           \
-   XPC_SCRIPTABLE_DONT_ASK_INSTANCE_FOR_SCRIPTABLE |                       \
-   XPC_SCRIPTABLE_DONT_REFLECT_INTERFACE_NAMES)
-
-#define DEFAULT_SCRIPTABLE_FLAGS                                           \
-  (DOM_BASE_SCRIPTABLE_FLAGS |                                             \
-   XPC_SCRIPTABLE_WANT_RESOLVE |                                           \
-   XPC_SCRIPTABLE_WANT_PRECREATE)
-
-#define DOM_DEFAULT_SCRIPTABLE_FLAGS                                       \
-  (DEFAULT_SCRIPTABLE_FLAGS |                                              \
-   XPC_SCRIPTABLE_DONT_ENUM_QUERY_INTERFACE |                              \
-   XPC_SCRIPTABLE_CLASSINFO_INTERFACES_ONLY)
-
-#endif /* nsIDOMClassInfo_h___ */
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -2135,22 +2135,16 @@ inline nsINode* NODE_FROM(C& aContent, D
 NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)
 
 inline nsISupports*
 ToSupports(nsINode* aPointer)
 {
   return aPointer;
 }
 
-inline nsISupports*
-ToCanonicalSupports(nsINode* aPointer)
-{
-  return aPointer;
-}
-
 // Some checks are faster to do on nsIContent or Element than on
 // nsINode, so spit out FromNode versions taking those types too.
 #define NS_IMPL_FROMNODE_GENERIC(_class, _check, _const)                 \
   template<typename T>                                                   \
   static auto FromNode(_const T& aNode)                                  \
     -> decltype(static_cast<_const _class*>(&aNode))                     \
   {                                                                      \
     return aNode._check ? static_cast<_const _class*>(&aNode) : nullptr; \
--- a/dom/base/nsRange.h
+++ b/dom/base/nsRange.h
@@ -582,20 +582,14 @@ protected:
 
   bool mIsPositioned : 1;
   bool mMaySpanAnonymousSubtrees : 1;
   bool mIsGenerated : 1;
   bool mCalledByJS : 1;
 };
 
 inline nsISupports*
-ToCanonicalSupports(nsRange* aRange)
-{
-  return static_cast<nsIDOMRange*>(aRange);
-}
-
-inline nsISupports*
 ToSupports(nsRange* aRange)
 {
   return static_cast<nsIDOMRange*>(aRange);
 }
 
 #endif /* nsRange_h___ */
--- a/dom/battery/BatteryManager.cpp
+++ b/dom/battery/BatteryManager.cpp
@@ -8,17 +8,16 @@
 #include <limits>
 #include "BatteryManager.h"
 #include "Constants.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/Hal.h"
 #include "mozilla/dom/BatteryManagerBinding.h"
 #include "mozilla/Preferences.h"
 #include "nsContentUtils.h"
-#include "nsIDOMClassInfo.h"
 #include "nsIDocument.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
 #define LEVELCHANGE_EVENT_NAME           NS_LITERAL_STRING("levelchange")
 #define CHARGINGCHANGE_EVENT_NAME        NS_LITERAL_STRING("chargingchange")
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -30,17 +30,17 @@
 #include "mozilla/Likely.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsAutoPtr.h"
 #include "nsIDocument.h"
 #include "nsIGlobalObject.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
 #include "nsISupportsImpl.h"
-#include "qsObjectHelper.h"
+#include "xpcObjectHelper.h"
 #include "xpcpublic.h"
 #include "nsIVariant.h"
 #include "mozilla/dom/FakeString.h"
 
 #include "nsWrapperCacheInlines.h"
 
 class nsGenericHTMLElement;
 class nsIJSID;
@@ -1319,17 +1319,17 @@ template <class T>
 MOZ_ALWAYS_INLINE bool
 HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
                                 T* value, JS::MutableHandle<JS::Value> rval)
 {
   if (JS_IsExceptionPending(cx)) {
     return false;
   }
 
-  qsObjectHelper helper(value, GetWrapperCache(value));
+  xpcObjectHelper helper(value, GetWrapperCache(value));
   return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
                                                   helper, nullptr, true);
 }
 
 // Helper for calling HandleNewBindingWrappingFailure with smart pointers
 // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
 
 template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
@@ -1553,17 +1553,17 @@ VariantToJsval(JSContext* aCx, nsIVarian
 // the nsWrapperCache for "p".
 template<class T>
 inline bool
 WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
            JS::MutableHandle<JS::Value> rval)
 {
   if (xpc_FastGetCachedWrapper(cx, cache, rval))
     return true;
-  qsObjectHelper helper(p, cache);
+  xpcObjectHelper helper(ToSupports(p), cache);
   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
   return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
 }
 
 // A specialization of the above for nsIVariant, because that needs to
 // do something different.
 template<>
 inline bool
@@ -1653,17 +1653,17 @@ WrapObject(JSContext* cx, JSObject& p, J
 // Given an object "p" that inherits from nsISupports, wrap it and return the
 // result.  Null is returned on wrapping failure.  This is somewhat similar to
 // WrapObject() above, but does NOT allow Xrays around the result, since we
 // don't want those for our parent object.
 template<typename T>
 static inline JSObject*
 WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
 {
-  qsObjectHelper helper(ToSupports(p), cache);
+  xpcObjectHelper helper(ToSupports(p), cache);
   JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
   JS::Rooted<JS::Value> v(cx);
   return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
          v.toObjectOrNull() :
          nullptr;
 }
 
 
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -187,20 +187,16 @@ DOMInterfaces = {
     'concrete': False,
     'nativeType': 'mozilla::css::GroupRule',
 },
 
 'CSSLexer': {
     'wrapperCache': False
 },
 
-'CSSPrimitiveValue': {
-    'nativeType': 'nsROCSSPrimitiveValue',
-},
-
 'CSSRule': {
     'concrete': False,
     'nativeType': 'mozilla::css::Rule'
 },
 
 'CSSStyleDeclaration': {
     'nativeType': 'nsICSSDeclaration'
 },
@@ -209,24 +205,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::BindingStyleRule',
 },
 
 'CSSStyleSheet': {
     'nativeType': 'mozilla::StyleSheet',
     'binaryNames': { 'ownerRule': 'DOMOwnerRule' },
 },
 
-'CSSValue': {
-    'concrete': False
-},
-
-'CSSValueList': {
-    'nativeType': 'nsDOMCSSValueList'
-},
-
 'DedicatedWorkerGlobalScope': {
     'headerFile': 'mozilla/dom/WorkerScope.h',
 },
 
 'DeviceAcceleration': {
     'headerFile': 'mozilla/dom/DeviceMotionEvent.h',
 },
 
@@ -713,38 +701,30 @@ DOMInterfaces = {
 
 'Range': {
     'nativeType': 'nsRange',
     'binaryNames': {
         '__stringifier': 'ToString'
     }
 },
 
-'Rect': {
-    'nativeType': 'nsDOMCSSRect',
-},
-
 'Request': {
     'binaryNames': {
         'headers': 'headers_',
         'referrerPolicy': 'referrerPolicy_'
     },
     'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text' ],
 },
 
 'Response': {
     'binaryNames': { 'headers': 'headers_' },
     'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text',
                            'clone', 'cloneUnfiltered' ],
 },
 
-'RGBColor': {
-    'nativeType': 'nsDOMCSSRGBColor',
-},
-
 'RTCDataChannel': {
     'nativeType': 'nsDOMDataChannel',
 },
 
 'Screen': {
     'nativeType': 'nsScreen',
 },
 
--- a/dom/bindings/ToJSValue.h
+++ b/dom/bindings/ToJSValue.h
@@ -182,17 +182,17 @@ typename EnableIf<!IsBaseOf<nsWrapperCac
                   IsBaseOf<nsISupports, T>::value, bool>::Type
 ToJSValue(JSContext* aCx,
           T& aArgument,
           JS::MutableHandle<JS::Value> aValue)
 {
   // Make sure we're called in a compartment
   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
 
-  qsObjectHelper helper(ToSupports(&aArgument), nullptr);
+  xpcObjectHelper helper(ToSupports(&aArgument));
   JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
   return XPCOMObjectToJsval(aCx, scope, helper, nullptr, true, aValue);
 }
 
 // Accept nsRefPtr/nsCOMPtr
 template <typename T>
 MOZ_MUST_USE bool
 ToJSValue(JSContext* aCx,
--- a/dom/clients/manager/ClientHandle.cpp
+++ b/dom/clients/manager/ClientHandle.cpp
@@ -44,24 +44,26 @@ ClientHandle::StartOp(const ClientOpCons
 {
   // Hold a ref to the client until the remote operation completes.  Otherwise
   // the ClientHandle might get de-refed and teardown the actor before we
   // get an answer.
   RefPtr<ClientHandle> kungFuGrip = this;
 
   MaybeExecute([aArgs, kungFuGrip, aRejectCallback,
                 resolve = Move(aResolveCallback)] (ClientHandleChild* aActor) {
+    MOZ_RELEASE_ASSERT(aActor);
     ClientHandleOpChild* actor =
       new ClientHandleOpChild(kungFuGrip, aArgs, Move(resolve),
                               Move(aRejectCallback));
     if (!aActor->SendPClientHandleOpConstructor(actor, aArgs)) {
       // Constructor failure will call reject callback via ActorDestroy()
       return;
     }
   }, [aRejectCallback] {
+    MOZ_RELEASE_ASSERT(aRejectCallback);
     aRejectCallback(NS_ERROR_DOM_INVALID_STATE_ERR);
   });
 }
 
 void
 ClientHandle::OnShutdownThing()
 {
   NS_ASSERT_OWNINGTHREAD(ClientHandle);
--- a/dom/clients/manager/ClientHandleOpChild.cpp
+++ b/dom/clients/manager/ClientHandleOpChild.cpp
@@ -34,15 +34,15 @@ ClientHandleOpChild::Recv__delete__(cons
 ClientHandleOpChild::ClientHandleOpChild(ClientHandle* aClientHandle,
                                          const ClientOpConstructorArgs& aArgs,
                                          const ClientOpCallback&& aResolveCallback,
                                          const ClientOpCallback&& aRejectCallback)
   : mClientHandle(aClientHandle)
   , mResolveCallback(Move(aResolveCallback))
   , mRejectCallback(Move(aRejectCallback))
 {
-  MOZ_DIAGNOSTIC_ASSERT(mClientHandle);
-  MOZ_DIAGNOSTIC_ASSERT(mResolveCallback);
-  MOZ_DIAGNOSTIC_ASSERT(mRejectCallback);
+  MOZ_RELEASE_ASSERT(mClientHandle);
+  MOZ_RELEASE_ASSERT(mResolveCallback);
+  MOZ_RELEASE_ASSERT(mRejectCallback);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/clients/manager/ClientManager.cpp
+++ b/dom/clients/manager/ClientManager.cpp
@@ -22,18 +22,23 @@ namespace mozilla {
 namespace dom {
 
 using mozilla::ipc::BackgroundChild;
 using mozilla::ipc::PBackgroundChild;
 using mozilla::ipc::PrincipalInfo;
 
 namespace {
 
-uint32_t kBadThreadLocalIndex = -1;
+const uint32_t kBadThreadLocalIndex = -1;
+const uint32_t kThreadLocalMagic1 = 0x8d57eea6;
+const uint32_t kThreadLocalMagic2 = 0x59f375c9;
+uint32_t sClientManagerThreadLocalMagic1 = kThreadLocalMagic1;
 uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex;
+uint32_t sClientManagerThreadLocalMagic2 = kThreadLocalMagic2;
+uint32_t sClientManagerThreadLocalIndexDuplicate = kBadThreadLocalIndex;
 
 } // anonymous namespace
 
 ClientManager::ClientManager()
 {
   PBackgroundChild* parentActor = BackgroundChild::GetOrCreateForCurrentThread();
   if (NS_WARN_IF(!parentActor)) {
     Shutdown();
@@ -74,17 +79,21 @@ ClientManager::ClientManager()
 }
 
 ClientManager::~ClientManager()
 {
   NS_ASSERT_OWNINGTHREAD(ClientManager);
 
   Shutdown();
 
-  MOZ_DIAGNOSTIC_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
+  MOZ_RELEASE_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   PRStatus status =
 #endif
     PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr);
   MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
 }
 
@@ -180,53 +189,65 @@ ClientManager::StartOp(const ClientOpCon
   RefPtr<ClientOpPromise> ref = promise.get();
   return ref.forget();
 }
 
 // static
 already_AddRefed<ClientManager>
 ClientManager::GetOrCreateForCurrentThread()
 {
-  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
   RefPtr<ClientManager> cm =
     static_cast<ClientManager*>(PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
 
   if (!cm) {
     cm = new ClientManager();
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     PRStatus status =
 #endif
       PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get());
     MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
   }
 
-  MOZ_ASSERT(cm);
+  MOZ_RELEASE_ASSERT(cm);
   return cm.forget();
 }
 
 WorkerPrivate*
 ClientManager::GetWorkerPrivate() const
 {
   NS_ASSERT_OWNINGTHREAD(ClientManager);
   MOZ_DIAGNOSTIC_ASSERT(GetActor());
   return GetActor()->GetWorkerPrivate();
 }
 
 // static
 void
 ClientManager::Startup()
 {
   MOZ_ASSERT(NS_IsMainThread());
+
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex);
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
+
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   PRStatus status =
 #endif
     PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr);
   MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
 
+  MOZ_RELEASE_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
+  sClientManagerThreadLocalIndexDuplicate = sClientManagerThreadLocalIndex;
+
   ClientPrefsInit();
 }
 
 // static
 UniquePtr<ClientSource>
 ClientManager::CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
                             nsIPrincipal* aPrincipal)
 {
--- a/dom/clients/manager/ClientThing.h
+++ b/dom/clients/manager/ClientThing.h
@@ -12,77 +12,99 @@ namespace mozilla {
 namespace dom {
 
 // Base class representing various Client "things" such as ClientHandle,
 // ClientSource, and ClientManager.  Currently it provides a common set
 // of code for handling activation and shutdown of IPC actors.
 template <typename ActorType>
 class ClientThing
 {
+  static const uint32_t kMagic1 = 0xC9FE2C9C;
+  static const uint32_t kMagic2 = 0x832072D4;
+
   ActorType* mActor;
+  uint32_t mMagic1;
+  uint32_t mMagic2;
   bool mShutdown;
 
 protected:
   ClientThing()
     : mActor(nullptr)
+    , mMagic1(kMagic1)
+    , mMagic2(kMagic2)
     , mShutdown(false)
   {
   }
 
   ~ClientThing()
   {
+    AssertIsValid();
     ShutdownThing();
+    mMagic1 = 0;
+    mMagic2 = 0;
+  }
+
+  void
+  AssertIsValid() const
+  {
+    MOZ_RELEASE_ASSERT(mMagic1 == kMagic1);
+    MOZ_RELEASE_ASSERT(mMagic2 == kMagic2);
   }
 
   // Return the current actor.
   ActorType*
   GetActor() const
   {
+    AssertIsValid();
     return mActor;
   }
 
   // Returns true if ShutdownThing() has been called.
   bool
   IsShutdown() const
   {
+    AssertIsValid();
     return mShutdown;
   }
 
   // Conditionally execute the given callable based on the current state.
   template<typename Callable>
   void
   MaybeExecute(const Callable& aSuccess,
                const std::function<void()>& aFailure = []{})
   {
+    AssertIsValid();
     if (mShutdown) {
       aFailure();
       return;
     }
     MOZ_DIAGNOSTIC_ASSERT(mActor);
     aSuccess(mActor);
   }
 
   // Attach activate the thing by attaching its underlying IPC actor.  This
   // will make the thing register as the actor's owner as well.  The actor
   // must call RevokeActor() to clear this weak back reference before its
   // destroyed.
   void
   ActivateThing(ActorType* aActor)
   {
+    AssertIsValid();
     MOZ_DIAGNOSTIC_ASSERT(aActor);
     MOZ_DIAGNOSTIC_ASSERT(!mActor);
     MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
     mActor = aActor;
     mActor->SetOwner(this);
   }
 
   // Start destroying the underlying actor and disconnect the thing.
   void
   ShutdownThing()
   {
+    AssertIsValid();
     if (mShutdown) {
       return;
     }
     mShutdown = true;
 
     // If we are shutdown before the actor, then clear the weak references
     // between the actor and the thing.
     if (mActor) {
@@ -101,16 +123,17 @@ protected:
     // by default do nothing
   }
 
 public:
   // Clear the weak references between the thing and its IPC actor.
   void
   RevokeActor(ActorType* aActor)
   {
+    AssertIsValid();
     MOZ_DIAGNOSTIC_ASSERT(mActor);
     MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
     mActor->RevokeOwner(this);
     mActor = nullptr;
 
     // Also consider the ClientThing shutdown.  We simply set the flag
     // instead of calling ShutdownThing() to avoid calling MaybeStartTeardown()
     // on the destroyed actor.
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -89,18 +89,18 @@ class ConsoleCallData final
 public:
   NS_INLINE_DECL_REFCOUNTING(ConsoleCallData)
 
   ConsoleCallData()
     : mMethodName(Console::MethodLog)
     , mTimeStamp(JS_Now() / PR_USEC_PER_MSEC)
     , mStartTimerValue(0)
     , mStartTimerStatus(Console::eTimerUnknown)
-    , mStopTimerDuration(0)
-    , mStopTimerStatus(Console::eTimerUnknown)
+    , mLogTimerDuration(0)
+    , mLogTimerStatus(Console::eTimerUnknown)
     , mCountValue(MAX_PAGE_COUNTERS)
     , mIDType(eUnknown)
     , mOuterIDNumber(0)
     , mInnerIDNumber(0)
     , mStatus(eUnused)
   {}
 
   bool
@@ -216,24 +216,24 @@ public:
   // They will be set on the owning thread and never touched again on that
   // thread. They will be used in order to create a ConsoleTimerStart dictionary
   // when console.time() is used.
   DOMHighResTimeStamp mStartTimerValue;
   nsString mStartTimerLabel;
   Console::TimerStatus mStartTimerStatus;
 
   // These values are set in the owning thread and they contain the duration,
-  // the name and the status of the StopTimer method. If status is false,
+  // the name and the status of the LogTimer method. If status is false,
   // something went wrong. They will be set on the owning thread and never
   // touched again on that thread. They will be used in order to create a
-  // ConsoleTimerEnd dictionary. This members are set when
-  // console.timeEnd() is called.
-  double mStopTimerDuration;
-  nsString mStopTimerLabel;
-  Console::TimerStatus mStopTimerStatus;
+  // ConsoleTimerLogOrEnd dictionary. This members are set when
+  // console.timeEnd() or console.timeLog() are called.
+  double mLogTimerDuration;
+  nsString mLogTimerLabel;
+  Console::TimerStatus mLogTimerStatus;
 
   // These 2 values are set by IncreaseCounter on the owning thread and they are
   // used CreateCounterValue. These members are set when console.count() is
   // called.
   nsString mCountLabel;
   uint32_t mCountValue;
 
   // The concept of outerID and innerID is misleading because when a
@@ -1226,40 +1226,52 @@ Console::GroupEnd(const GlobalObject& aG
 {
   const Sequence<JS::Value> data;
   Method(aGlobal, MethodGroupEnd, NS_LITERAL_STRING("groupEnd"), data);
 }
 
 /* static */ void
 Console::Time(const GlobalObject& aGlobal, const nsAString& aLabel)
 {
-  StringMethod(aGlobal, aLabel, MethodTime, NS_LITERAL_STRING("time"));
+  StringMethod(aGlobal, aLabel, Sequence<JS::Value>(), MethodTime,
+               NS_LITERAL_STRING("time"));
 }
 
 /* static */ void
 Console::TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel)
 {
-  StringMethod(aGlobal, aLabel, MethodTimeEnd, NS_LITERAL_STRING("timeEnd"));
+  StringMethod(aGlobal, aLabel, Sequence<JS::Value>(), MethodTimeEnd,
+               NS_LITERAL_STRING("timeEnd"));
+}
+
+/* static */ void
+Console::TimeLog(const GlobalObject& aGlobal, const nsAString& aLabel,
+                 const Sequence<JS::Value>& aData)
+{
+  StringMethod(aGlobal, aLabel, aData, MethodTimeLog,
+               NS_LITERAL_STRING("timeLog"));
 }
 
 /* static */ void
 Console::StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
-                      MethodName aMethodName, const nsAString& aMethodString)
+                      const Sequence<JS::Value>& aData, MethodName aMethodName,
+                      const nsAString& aMethodString)
 {
   RefPtr<Console> console = GetConsole(aGlobal);
   if (!console) {
     return;
   }
 
-  console->StringMethodInternal(aGlobal.Context(), aLabel, aMethodName,
+  console->StringMethodInternal(aGlobal.Context(), aLabel, aData, aMethodName,
                                 aMethodString);
 }
 
 void
 Console::StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
+                              const Sequence<JS::Value>& aData,
                               MethodName aMethodName,
                               const nsAString& aMethodString)
 {
   ConsoleCommon::ClearException ce(aCx);
 
   Sequence<JS::Value> data;
   SequenceRooter<JS::Value> rooter(aCx, &data);
 
@@ -1267,16 +1279,22 @@ Console::StringMethodInternal(JSContext*
   if (!dom::ToJSValue(aCx, aLabel, &value)) {
     return;
   }
 
   if (!data.AppendElement(value, fallible)) {
     return;
   }
 
+  for (uint32_t i = 0; i < aData.Length(); ++i) {
+    if (!data.AppendElement(aData[i], fallible)) {
+      return;
+    }
+  }
+
   MethodInternal(aCx, aMethodName, aMethodString, data);
 }
 
 /* static */ void
 Console::TimeStamp(const GlobalObject& aGlobal,
                    const JS::Handle<JS::Value> aData)
 {
   JSContext* cx = aGlobal.Context();
@@ -1417,17 +1435,18 @@ Console::Assert(const GlobalObject& aGlo
   if (!aCondition) {
     Method(aGlobal, MethodAssert, NS_LITERAL_STRING("assert"), aData);
   }
 }
 
 /* static */ void
 Console::Count(const GlobalObject& aGlobal, const nsAString& aLabel)
 {
-  StringMethod(aGlobal, aLabel, MethodCount, NS_LITERAL_STRING("count"));
+  StringMethod(aGlobal, aLabel, Sequence<JS::Value>(), MethodCount,
+               NS_LITERAL_STRING("count"));
 }
 
 namespace {
 
 void
 StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
                        ConsoleStackEntry& aStackEntry)
 {
@@ -1568,36 +1587,46 @@ Console::MethodInternal(JSContext* aCx, 
     // nsIStackFrame is not threadsafe, so we need to snapshot it now,
     // before we post our runnable to the main thread.
     callData->mReifiedStack.emplace();
     ReifyStack(aCx, stack, *callData->mReifiedStack);
   }
 
   DOMHighResTimeStamp monotonicTimer;
 
-  // Monotonic timer for 'time' and 'timeEnd'
+  // Monotonic timer for 'time', 'timeLog' and 'timeEnd'
   if ((aMethodName == MethodTime ||
+       aMethodName == MethodTimeLog ||
        aMethodName == MethodTimeEnd ||
        aMethodName == MethodTimeStamp) &&
       !MonotonicTimer(aCx, aMethodName, aData, &monotonicTimer)) {
     return;
   }
 
   if (aMethodName == MethodTime && !aData.IsEmpty()) {
     callData->mStartTimerStatus = StartTimer(aCx, aData[0],
                                              monotonicTimer,
                                              callData->mStartTimerLabel,
                                              &callData->mStartTimerValue);
   }
 
   else if (aMethodName == MethodTimeEnd && !aData.IsEmpty()) {
-    callData->mStopTimerStatus = StopTimer(aCx, aData[0],
-                                           monotonicTimer,
-                                           callData->mStopTimerLabel,
-                                           &callData->mStopTimerDuration);
+    callData->mLogTimerStatus = LogTimer(aCx, aData[0],
+                                         monotonicTimer,
+                                         callData->mLogTimerLabel,
+                                         &callData->mLogTimerDuration,
+                                         true /* Cancel timer */);
+  }
+
+  else if (aMethodName == MethodTimeLog && !aData.IsEmpty()) {
+    callData->mLogTimerStatus = LogTimer(aCx, aData[0],
+                                         monotonicTimer,
+                                         callData->mLogTimerLabel,
+                                         &callData->mLogTimerDuration,
+                                         false /* Cancel timer */);
   }
 
   else if (aMethodName == MethodCount) {
     callData->mCountValue = IncreaseCounter(aCx, aData, callData->mCountLabel);
     if (!callData->mCountValue) {
       return;
     }
   }
@@ -1858,20 +1887,21 @@ Console::PopulateConsoleNotificationInTh
     }
   }
 
   else if (aData->mMethodName == MethodTime && !aArguments.IsEmpty()) {
     event.mTimer = CreateStartTimerValue(aCx, aData->mStartTimerLabel,
                                          aData->mStartTimerStatus);
   }
 
-  else if (aData->mMethodName == MethodTimeEnd && !aArguments.IsEmpty()) {
-    event.mTimer = CreateStopTimerValue(aCx, aData->mStopTimerLabel,
-                                        aData->mStopTimerDuration,
-                                        aData->mStopTimerStatus);
+  else if ((aData->mMethodName == MethodTimeEnd ||
+            aData->mMethodName == MethodTimeLog) && !aArguments.IsEmpty()) {
+    event.mTimer = CreateLogOrEndTimerValue(aCx, aData->mLogTimerLabel,
+                                            aData->mLogTimerDuration,
+                                            aData->mLogTimerStatus);
   }
 
   else if (aData->mMethodName == MethodCount) {
     event.mCounter = CreateCounterValue(aCx, aData->mCountLabel,
                                         aData->mCountValue);
   }
 
   JSAutoCompartment ac2(aCx, targetScope);
@@ -2316,20 +2346,21 @@ Console::CreateStartTimerValue(JSContext
   if (!ToJSValue(aCx, timer, &value)) {
     return JS::UndefinedValue();
   }
 
   return value;
 }
 
 Console::TimerStatus
-Console::StopTimer(JSContext* aCx, const JS::Value& aName,
-                   DOMHighResTimeStamp aTimestamp,
-                   nsAString& aTimerLabel,
-                   double* aTimerDuration)
+Console::LogTimer(JSContext* aCx, const JS::Value& aName,
+                  DOMHighResTimeStamp aTimestamp,
+                  nsAString& aTimerLabel,
+                  double* aTimerDuration,
+                  bool aCancelTimer)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aTimerDuration);
 
   *aTimerDuration = 0;
 
   JS::Rooted<JS::Value> name(aCx, aName);
   JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, name));
@@ -2340,34 +2371,42 @@ Console::StopTimer(JSContext* aCx, const
   nsAutoJSString key;
   if (NS_WARN_IF(!key.init(aCx, jsString))) {
     return eTimerJSException;
   }
 
   aTimerLabel = key;
 
   DOMHighResTimeStamp value = 0;
-  if (!mTimerRegistry.Remove(key, &value)) {
-    NS_WARNING("mTimerRegistry entry not found");
-    return eTimerDoesntExist;
+
+  if (aCancelTimer) {
+    if (!mTimerRegistry.Remove(key, &value)) {
+      NS_WARNING("mTimerRegistry entry not found");
+      return eTimerDoesntExist;
+    }
+  } else {
+    if (!mTimerRegistry.Get(key, &value)) {
+      NS_WARNING("mTimerRegistry entry not found");
+      return eTimerDoesntExist;
+    }
   }
 
   *aTimerDuration = aTimestamp - value;
   return eTimerDone;
 }
 
 JS::Value
-Console::CreateStopTimerValue(JSContext* aCx, const nsAString& aLabel,
-                              double aDuration, TimerStatus aStatus) const
+Console::CreateLogOrEndTimerValue(JSContext* aCx, const nsAString& aLabel,
+                                  double aDuration, TimerStatus aStatus) const
 {
   if (aStatus != eTimerDone) {
     return CreateTimerError(aCx, aLabel, aStatus);
   }
 
-  RootedDictionary<ConsoleTimerEnd> timer(aCx);
+  RootedDictionary<ConsoleTimerLogOrEnd> timer(aCx);
   timer.mName = aLabel;
   timer.mDuration = aDuration;
 
   JS::Rooted<JS::Value> value(aCx);
   if (!ToJSValue(aCx, timer, &value)) {
     return JS::UndefinedValue();
   }
 
@@ -2991,16 +3030,17 @@ Console::WebIDLLogLevelToInteger(Console
 {
   switch (aLevel) {
     case ConsoleLogLevel::All: return 0;
     case ConsoleLogLevel::Debug: return 2;
     case ConsoleLogLevel::Log: return 3;
     case ConsoleLogLevel::Info: return 3;
     case ConsoleLogLevel::Clear: return 3;
     case ConsoleLogLevel::Trace: return 3;
+    case ConsoleLogLevel::TimeLog: return 3;
     case ConsoleLogLevel::TimeEnd: return 3;
     case ConsoleLogLevel::Time: return 3;
     case ConsoleLogLevel::Group: return 3;
     case ConsoleLogLevel::GroupEnd: return 3;
     case ConsoleLogLevel::Profile: return 3;
     case ConsoleLogLevel::ProfileEnd: return 3;
     case ConsoleLogLevel::Dir: return 3;
     case ConsoleLogLevel::Dirxml: return 3;
@@ -3028,16 +3068,17 @@ Console::InternalLogLevelToInteger(Metho
     case MethodTable: return 3;
     case MethodTrace: return 3;
     case MethodDir: return 3;
     case MethodDirxml: return 3;
     case MethodGroup: return 3;
     case MethodGroupCollapsed: return 3;
     case MethodGroupEnd: return 3;
     case MethodTime: return 3;
+    case MethodTimeLog: return 3;
     case MethodTimeEnd: return 3;
     case MethodTimeStamp: return 3;
     case MethodAssert: return 3;
     case MethodCount: return 3;
     case MethodClear: return 3;
     case MethodProfile: return 3;
     case MethodProfileEnd: return 3;
     default:
--- a/dom/console/Console.h
+++ b/dom/console/Console.h
@@ -92,16 +92,20 @@ public:
 
   static void
   GroupEnd(const GlobalObject& aGlobal);
 
   static void
   Time(const GlobalObject& aGlobal, const nsAString& aLabel);
 
   static void
+  TimeLog(const GlobalObject& aGlobal, const nsAString& aLabel,
+          const Sequence<JS::Value>& aData);
+
+  static void
   TimeEnd(const GlobalObject& aGlobal, const nsAString& aLabel);
 
   static void
   TimeStamp(const GlobalObject& aGlobal, const JS::Handle<JS::Value> aData);
 
   static void
   Profile(const GlobalObject& aGlobal, const Sequence<JS::Value>& aData);
 
@@ -154,16 +158,17 @@ private:
     MethodTable,
     MethodTrace,
     MethodDir,
     MethodDirxml,
     MethodGroup,
     MethodGroupCollapsed,
     MethodGroupEnd,
     MethodTime,
+    MethodTimeLog,
     MethodTimeEnd,
     MethodTimeStamp,
     MethodAssert,
     MethodCount,
     MethodClear,
     MethodProfile,
     MethodProfileEnd,
   };
@@ -188,20 +193,22 @@ private:
          const nsAString& aString, const Sequence<JS::Value>& aData);
 
   void
   MethodInternal(JSContext* aCx, MethodName aName,
                  const nsAString& aString, const Sequence<JS::Value>& aData);
 
   static void
   StringMethod(const GlobalObject& aGlobal, const nsAString& aLabel,
-               MethodName aMethodName, const nsAString& aMethodString);
+               const Sequence<JS::Value>& aData, MethodName aMethodName,
+               const nsAString& aMethodString);
 
   void
   StringMethodInternal(JSContext* aCx, const nsAString& aLabel,
+                       const Sequence<JS::Value>& aData,
                        MethodName aMethodName, const nsAString& aMethodString);
 
   // This method must receive aCx and aArguments in the same JSCompartment.
   void
   ProcessCallData(JSContext* aCx,
                   ConsoleCallData* aData,
                   const Sequence<JS::Value>& aArguments);
 
@@ -312,43 +319,45 @@ private:
   // thread.
   // * aCx - this is the context that will root the returned value.
   // * aTimerLabel - this label must be what StartTimer received as aTimerLabel.
   // * aTimerStatus - the return value of StartTimer.
   JS::Value
   CreateStartTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
                         TimerStatus aTimerStatus) const;
 
-  // StopTimer follows the same pattern as StartTimer: it runs on the
+  // LogTimer follows the same pattern as StartTimer: it runs on the
   // owning thread and populates aTimerLabel and aTimerDuration, used by
-  // CreateStopTimerValue.
+  // CreateLogOrEndTimerValue.
   // * aCx - the JSContext rooting aName.
   // * aName - this is (should be) the name of the timer as JS::Value.
   // * aTimestamp - the monotonicTimer for this context taken from
   //                performance.now().
   // * aTimerLabel - This label will be populated with the aName converted to a
   //                 string.
   // * aTimerDuration - the difference between aTimestamp and when the timer
   //                    started (see StartTimer).
+  // * aCancelTimer - if true, the timer is removed from the table.
   TimerStatus
-  StopTimer(JSContext* aCx, const JS::Value& aName,
-            DOMHighResTimeStamp aTimestamp,
-            nsAString& aTimerLabel,
-            double* aTimerDuration);
+  LogTimer(JSContext* aCx, const JS::Value& aName,
+           DOMHighResTimeStamp aTimestamp,
+           nsAString& aTimerLabel,
+           double* aTimerDuration,
+           bool aCancelTimer);
 
   // This method generates a ConsoleTimerEnd dictionary exposed as JS::Value, or
-  // a ConsoleTimerError dictionary if aTimerStatus is false. See StopTimer.
+  // a ConsoleTimerError dictionary if aTimerStatus is false. See LogTimer.
   // * aCx - this is the context that will root the returned value.
-  // * aTimerLabel - this label must be what StopTimer received as aTimerLabel.
-  // * aTimerDuration - this is what StopTimer received as aTimerDuration
-  // * aTimerStatus - the return value of StopTimer.
+  // * aTimerLabel - this label must be what LogTimer received as aTimerLabel.
+  // * aTimerDuration - this is what LogTimer received as aTimerDuration
+  // * aTimerStatus - the return value of LogTimer.
   JS::Value
-  CreateStopTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
-                       double aTimerDuration,
-                       TimerStatus aTimerStatus) const;
+  CreateLogOrEndTimerValue(JSContext* aCx, const nsAString& aTimerLabel,
+                           double aTimerDuration,
+                           TimerStatus aTimerStatus) const;
 
   // The method populates a Sequence from an array of JS::Value.
   bool
   ArgumentsToValueList(const Sequence<JS::Value>& aData,
                        Sequence<JS::Value>& aSequence) const;
 
   // This method follows the same pattern as StartTimer: its runs on the owning
   // thread and populate aCountLabel, used by CreateCounterValue. Returns
--- a/dom/console/ConsoleInstance.cpp
+++ b/dom/console/ConsoleInstance.cpp
@@ -142,24 +142,34 @@ ConsoleInstance::GroupEnd(JSContext* aCx
   const Sequence<JS::Value> data;
   mConsole->MethodInternal(aCx, Console::MethodGroupEnd,
                            NS_LITERAL_STRING("groupEnd"), data);
 }
 
 void
 ConsoleInstance::Time(JSContext* aCx, const nsAString& aLabel)
 {
-  mConsole->StringMethodInternal(aCx, aLabel, Console::MethodTime,
+  mConsole->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+                                 Console::MethodTime,
                                  NS_LITERAL_STRING("time"));
 }
 
 void
+ConsoleInstance::TimeLog(JSContext* aCx, const nsAString& aLabel,
+                         const Sequence<JS::Value>& aData)
+{
+  mConsole->StringMethodInternal(aCx, aLabel, aData, Console::MethodTimeLog,
+                                 NS_LITERAL_STRING("timeLog"));
+}
+
+void
 ConsoleInstance::TimeEnd(JSContext* aCx, const nsAString& aLabel)
 {
-  mConsole->StringMethodInternal(aCx, aLabel, Console::MethodTimeEnd,
+  mConsole->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+                                 Console::MethodTimeEnd,
                                  NS_LITERAL_STRING("timeEnd"));
 }
 
 void
 ConsoleInstance::TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData)
 {
   ConsoleCommon::ClearException ce(aCx);
 
@@ -196,17 +206,18 @@ ConsoleInstance::Assert(JSContext* aCx, 
     mConsole->MethodInternal(aCx, Console::MethodAssert,
                              NS_LITERAL_STRING("assert"), aData);
   }
 }
 
 void
 ConsoleInstance::Count(JSContext* aCx, const nsAString& aLabel)
 {
-  mConsole->StringMethodInternal(aCx, aLabel, Console::MethodCount,
+  mConsole->StringMethodInternal(aCx, aLabel, Sequence<JS::Value>(),
+                                 Console::MethodCount,
                                  NS_LITERAL_STRING("count"));
 }
 
 void
 ConsoleInstance::Clear(JSContext* aCx)
 {
   const Sequence<JS::Value> data;
   mConsole->MethodInternal(aCx, Console::MethodClear,
--- a/dom/console/ConsoleInstance.h
+++ b/dom/console/ConsoleInstance.h
@@ -70,16 +70,20 @@ public:
 
   void
   GroupEnd(JSContext* aCx);
 
   void
   Time(JSContext* aCx, const nsAString& aLabel);
 
   void
+  TimeLog(JSContext* aCx, const nsAString& aLabel,
+          const Sequence<JS::Value>& aData);
+
+  void
   TimeEnd(JSContext* aCx, const nsAString& aLabel);
 
   void
   TimeStamp(JSContext* aCx, const JS::Handle<JS::Value> aData);
 
   void
   Profile(JSContext* aCx, const Sequence<JS::Value>& aData);
 
--- a/dom/console/tests/mochitest.ini
+++ b/dom/console/tests/mochitest.ini
@@ -5,8 +5,9 @@ support-files =
 [test_bug659625.html]
 [test_bug978522.html]
 [test_bug979109.html]
 [test_bug989665.html]
 [test_consoleEmptyStack.html]
 [test_console_binding.html]
 [test_console_proto.html]
 [test_devtools_pref.html]
+[test_timer.html]
new file mode 100644
--- /dev/null
+++ b/dom/console/tests/test_timer.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test for timeStart/timeLog/timeEnd in console</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+  <script type="application/javascript">
+
+SimpleTest.waitForExplicitFinish();
+
+function ConsoleListener() {
+  SpecialPowers.addObserver(this, "console-api-log-event");
+}
+
+ConsoleListener.prototype = {
+  observe(aSubject, aTopic, aData) {
+    let obj = aSubject.wrappedJSObject;
+    if (obj.arguments[0] != 'test') {
+      return;
+    }
+
+    if (!this._cb) {
+      ok(false, "Callback not set!");
+      return;
+    }
+
+    if (!this._cb(obj)) {
+      return;
+    }
+
+    this._cb = null;
+    this._resolve();
+  },
+
+  shutdown() {
+    SpecialPowers.removeObserver(this, "console-api-log-event");
+  },
+
+  waitFor(cb) {
+    return new Promise(resolve => {
+      this._cb = cb;
+      this._resolve = resolve;
+    });
+  },
+};
+
+let listener = new ConsoleListener();
+
+// Timer creation:
+async function runTest() {
+  let cl = listener.waitFor(obj => {
+    return ("timer" in obj) &&
+           ("name" in obj.timer) &&
+           obj.timer.name == 'test';
+  });
+
+  console.time('test');
+  await cl;
+  ok(true, "Console.time received!");
+
+  // Timer check:
+  cl = listener.waitFor(obj => {
+    return ("timer" in obj) &&
+           ("name" in obj.timer) &&
+           obj.timer.name == 'test' &&
+           ("duration" in obj.timer) &&
+           obj.timer.duration > 0 &&
+           obj.arguments[1] == 1 &&
+           obj.arguments[2] == 2 &&
+           obj.arguments[3] == 3 &&
+           obj.arguments[4] == 4;
+  });
+  console.timeLog('test', 1, 2, 3, 4);
+  await cl;
+  ok(true, "Console.timeLog received!");
+
+  // Time deleted:
+  cl = listener.waitFor(obj => {
+    return ("timer" in obj) &&
+           ("name" in obj.timer) &&
+           obj.timer.name == 'test' &&
+           ("duration" in obj.timer) &&
+           obj.timer.duration > 0;
+  });
+  console.timeEnd('test');
+  await cl;
+  ok(true, "Console.timeEnd received!");
+
+  // Here an error:
+  cl = listener.waitFor(obj => {
+    return ("timer" in obj) &&
+           ("name" in obj.timer) &&
+           obj.timer.name == 'test' &&
+           ("error" in obj.timer);
+  });
+  console.timeLog('test');
+  await cl;
+  ok(true, "Console.time with error received!");
+}
+
+runTest().then(() => {
+  listener.shutdown();
+  SimpleTest.finish();
+});
+
+  </script>
+</body>
+</html>
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -5364,16 +5364,64 @@ EventStateManager::ResetLastOverForConte
   if (aElemWrapper && aElemWrapper->mLastOverElement &&
       nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
                                             aContent)) {
     aElemWrapper->mLastOverElement = nullptr;
   }
 }
 
 void
+EventStateManager::RemoveNodeFromChainIfNeeded(EventStates aState,
+                                               nsIContent* aContentRemoved,
+                                               bool aNotify)
+{
+  MOZ_ASSERT(aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE);
+  if (!aContentRemoved->IsElement() ||
+      !aContentRemoved->AsElement()->State().HasState(aState)) {
+    return;
+  }
+
+  nsCOMPtr<nsIContent>& leaf =
+    aState == NS_EVENT_STATE_HOVER ? mHoverContent : mActiveContent;
+
+  MOZ_ASSERT(leaf);
+  // XBL Likes to unbind content without notifying, thus the
+  // NODE_IS_ANONYMOUS_ROOT check...
+  MOZ_ASSERT(nsContentUtils::ContentIsFlattenedTreeDescendantOf(
+               leaf, aContentRemoved) ||
+             leaf->SubtreeRoot()->HasFlag(NODE_IS_ANONYMOUS_ROOT));
+
+  nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
+  MOZ_ASSERT_IF(newLeaf,
+                newLeaf->IsElement() &&
+                newLeaf->AsElement()->State().HasState(aState));
+  if (aNotify) {
+    SetContentState(newLeaf, aState);
+  } else {
+    // We don't update the removed content's state here, since removing NAC
+    // happens from layout and we don't really want to notify at that point or
+    // what not.
+    //
+    // Also, NAC is not observable and NAC being removed will go away soon.
+    leaf = newLeaf;
+  }
+  MOZ_ASSERT(leaf == newLeaf);
+}
+
+void
+EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent)
+{
+  // FIXME(bug 1450250): <svg:use> is nasty.
+  MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree() ||
+             aContent->GetParentNode()->IsSVGElement(nsGkAtoms::use));
+  RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_HOVER, aContent, false);
+  RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_ACTIVE, aContent, false);
+}
+
+void
 EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
 {
   /*
    * Anchor and area elements when focused or hovered might make the UI to show
    * the current link. We want to make sure that the UI gets informed when they
    * are actually removed from the DOM.
    */
   if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
@@ -5387,29 +5435,18 @@ EventStateManager::ContentRemoved(nsIDoc
   IMEStateManager::OnRemoveContent(mPresContext, aContent);
 
   // inform the focus manager that the content is being removed. If this
   // content is focused, the focus will be removed without firing events.
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm)
     fm->ContentRemoved(aDocument, aContent);
 
-  if (mHoverContent &&
-      nsContentUtils::ContentIsFlattenedTreeDescendantOf(mHoverContent, aContent)) {
-    // Since hover is hierarchical, set the current hover to the
-    // content's parent node.
-    SetContentState(aContent->GetFlattenedTreeParent(), NS_EVENT_STATE_HOVER);
-  }
-
-  if (mActiveContent &&
-      nsContentUtils::ContentIsFlattenedTreeDescendantOf(mActiveContent, aContent)) {
-    // Active is hierarchical, so set the current active to the
-    // content's parent node.
-    SetContentState(aContent->GetFlattenedTreeParent(), NS_EVENT_STATE_ACTIVE);
-  }
+  RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_HOVER, aContent, true);
+  RemoveNodeFromChainIfNeeded(NS_EVENT_STATE_ACTIVE, aContent, true);
 
   if (sDragOverContent &&
       sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
       nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent, aContent)) {
     sDragOverContent = nullptr;
   }
 
   PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -143,16 +143,18 @@ public:
    * @return  Whether the content was able to change all states. Returns false
    *                  if a resulting DOM event causes the content node passed in
    *                  to not change states. Note, the frame for the content may
    *                  change as a result of the content state change, because of
    *                  frame reconstructions that may occur, but this does not
    *                  affect the return value.
    */
   bool SetContentState(nsIContent* aContent, EventStates aState);
+
+  void NativeAnonymousContentRemoved(nsIContent* aAnonContent);
   void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
 
   bool EventStatusOK(WidgetGUIEvent* aEvent);
 
   /**
    * EventStateManager stores IMEContentObserver while it's observing contents.
    * Following mehtods are called by IMEContentObserver when it starts to
    * observe or stops observing the content.
@@ -1082,16 +1084,24 @@ protected:
   bool HandleCrossProcessEvent(WidgetEvent* aEvent,
                                nsEventStatus* aStatus);
 
   void ReleaseCurrentIMEContentObserver();
 
   void HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
 
 private:
+  // Removes a node from the :hover / :active chain if needed, notifying if the
+  // node is not a NAC subtree.
+  //
+  // Only meant to be called from ContentRemoved and
+  // NativeAnonymousContentRemoved.
+  void RemoveNodeFromChainIfNeeded(EventStates aState,
+                                   nsIContent* aContentRemoved,
+                                   bool aNotify);
 
   bool IsEventOutsideDragThreshold(WidgetInputEvent* aEvent) const;
 
   static inline void DoStateChange(dom::Element* aElement,
                                    EventStates aState, bool aAddState);
   static inline void DoStateChange(nsIContent* aContent, EventStates aState,
                                    bool aAddState);
   static void UpdateAncestorState(nsIContent* aStartNode,
--- a/dom/html/nsGenericHTMLElement.h
+++ b/dom/html/nsGenericHTMLElement.h
@@ -1341,21 +1341,9 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(TextArea)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Tfoot)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Thead)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Time)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Title)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Track)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Unknown)
 NS_DECLARE_NS_NEW_HTML_ELEMENT(Video)
 
-inline nsISupports*
-ToSupports(nsGenericHTMLElement* aHTMLElement)
-{
-  return static_cast<nsIContent*>(aHTMLElement);
-}
-
-inline nsISupports*
-ToCanonicalSupports(nsGenericHTMLElement* aHTMLElement)
-{
-  return static_cast<nsIContent*>(aHTMLElement);
-}
-
 #endif /* nsGenericHTMLElement_h___ */
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1884,74 +1884,59 @@ nsHTMLDocument::CaptureEvents()
 }
 
 void
 nsHTMLDocument::ReleaseEvents()
 {
   WarnOnceAbout(nsIDocument::eUseOfReleaseEvents);
 }
 
-nsISupports*
-nsHTMLDocument::ResolveName(const nsAString& aName, nsWrapperCache **aCache)
+bool
+nsHTMLDocument::ResolveName(JSContext* aCx, const nsAString& aName,
+                            JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
 {
   nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aName);
   if (!entry) {
-    *aCache = nullptr;
-    return nullptr;
+    return false;
   }
 
   nsBaseContentList *list = entry->GetNameContentList();
   uint32_t length = list ? list->Length() : 0;
 
+  nsIContent *node;
   if (length > 0) {
-    if (length == 1) {
-      // Only one element in the list, return the element instead of returning
-      // the list.
-      nsIContent *node = list->Item(0);
-      *aCache = node;
-      return node;
+    if (length > 1) {
+      // The list contains more than one element, return the whole list.
+      if (!ToJSValue(aCx, list, aRetval)) {
+        aError.NoteJSContextException(aCx);
+        return false;
+      }
+      return true;
     }
 
-    // The list contains more than one element, return the whole list.
-    *aCache = list;
-    return list;
-  }
-
-  // No named items were found, see if there's one registerd by id for aName.
-  Element *e = entry->GetIdElement();
-
-  if (e && nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(e)) {
-    *aCache = e;
-    return e;
+    // Only one element in the list, return the element instead of returning
+    // the list.
+    node = list->Item(0);
+  } else {
+    // No named items were found, see if there's one registerd by id for aName.
+    Element *e = entry->GetIdElement();
+  
+    if (!e || !nsGenericHTMLElement::ShouldExposeIdAsHTMLDocumentProperty(e)) {
+      return false;
+    }
+
+    node = e;
   }
 
-  *aCache = nullptr;
-  return nullptr;
-}
-
-void
-nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
-                            JS::MutableHandle<JSObject*> aRetval,
-                            ErrorResult& rv)
-{
-  nsWrapperCache* cache;
-  nsISupports* supp = ResolveName(aName, &cache);
-  if (!supp) {
-    aFound = false;
-    aRetval.set(nullptr);
-    return;
+  if (!ToJSValue(aCx, node, aRetval)) {
+    aError.NoteJSContextException(aCx);
+    return false;
   }
 
-  JS::Rooted<JS::Value> val(cx);
-  if (!dom::WrapObject(cx, supp, cache, nullptr, &val)) {
-    rv.Throw(NS_ERROR_OUT_OF_MEMORY);
-    return;
-  }
-  aFound = true;
-  aRetval.set(&val.toObject());
+  return true;
 }
 
 void
 nsHTMLDocument::GetSupportedNames(nsTArray<nsString>& aNames)
 {
   for (auto iter = mIdentifierMap.Iter(); !iter.Done(); iter.Next()) {
     nsIdentifierMapEntry* entry = iter.Get();
     if (entry->HasNameElement() ||
--- a/dom/html/nsHTMLDocument.h
+++ b/dom/html/nsHTMLDocument.h
@@ -74,17 +74,19 @@ public:
 
   nsContentList* GetExistingForms() const
   {
     return mForms;
   }
 
   mozilla::dom::HTMLAllCollection* All();
 
-  nsISupports* ResolveName(const nsAString& aName, nsWrapperCache **aCache);
+  // Returns whether an object was found for aName.
+  bool ResolveName(JSContext* aCx, const nsAString& aName,
+                   JS::MutableHandle<JS::Value> aRetval, mozilla::ErrorResult& aError);
 
   virtual void AddedForm() override;
   virtual void RemovedForm() override;
   virtual int32_t GetNumFormsSynchronous() override;
   virtual void TearingDownEditor() override;
   virtual void SetIsXHTML(bool aXHTML) override
   {
     mType = (aXHTML ? eXHTML : eHTML);
@@ -146,17 +148,23 @@ public:
   void GetDomain(nsAString& aDomain);
   void SetDomain(const nsAString& aDomain, mozilla::ErrorResult& rv);
   bool IsRegistrableDomainSuffixOfOrEqualTo(const nsAString& aHostSuffixString,
                                             const nsACString& aOrigHost);
   void GetCookie(nsAString& aCookie, mozilla::ErrorResult& rv);
   void SetCookie(const nsAString& aCookie, mozilla::ErrorResult& rv);
   void NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
                    JS::MutableHandle<JSObject*> aRetval,
-                   mozilla::ErrorResult& rv);
+                   mozilla::ErrorResult& rv)
+  {
+    JS::Rooted<JS::Value> v(cx);
+    if ((aFound = ResolveName(cx, aName, &v, rv))) {
+      aRetval.set(v.toObjectOrNull());
+    }
+  }
   void GetSupportedNames(nsTArray<nsString>& aNames);
   already_AddRefed<nsIDocument> Open(JSContext* cx,
                                      const mozilla::dom::Optional<nsAString>& /* unused */,
                                      const nsAString& aReplace,
                                      mozilla::ErrorResult& aError);
   already_AddRefed<nsPIDOMWindowOuter>
   Open(JSContext* cx,
        const nsAString& aURL,
--- a/dom/network/Connection.cpp
+++ b/dom/network/Connection.cpp
@@ -2,17 +2,16 @@
 /* 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 "Connection.h"
 #include "ConnectionMainThread.h"
 #include "ConnectionWorker.h"
-#include "nsIDOMClassInfo.h"
 #include "Constants.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/dom/WorkerPrivate.h"
 
 /**
  * We have to use macros here because our leak analysis tool things we are
  * leaking strings when we have |static const nsString|. Sad :(
  */
--- a/dom/serviceworkers/ServiceWorker.cpp
+++ b/dom/serviceworkers/ServiceWorker.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ServiceWorker.h"
 
 #include "nsIDocument.h"
 #include "nsPIDOMWindow.h"
+#include "ServiceWorkerImpl.h"
 #include "ServiceWorkerManager.h"
 #include "ServiceWorkerPrivate.h"
 
 #include "mozilla/dom/DOMPrefs.h"
 #include "mozilla/dom/ClientIPCTypes.h"
 #include "mozilla/dom/ClientState.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
@@ -57,17 +58,18 @@ ServiceWorker::Create(nsIGlobalObject* a
     return ref.forget();
   }
 
   RefPtr<ServiceWorkerInfo> info = reg->GetByDescriptor(aDescriptor);
   if (!info) {
     return ref.forget();
   }
 
-  ref = new ServiceWorker(aOwner, aDescriptor, info);
+  RefPtr<ServiceWorker::Inner> inner = new ServiceWorkerImpl(info);
+  ref = new ServiceWorker(aOwner, aDescriptor, inner);
   return ref.forget();
 }
 
 ServiceWorker::ServiceWorker(nsIGlobalObject* aGlobal,
                              const ServiceWorkerDescriptor& aDescriptor,
                              ServiceWorker::Inner* aInner)
   : DOMEventTargetHelper(aGlobal)
   , mDescriptor(aDescriptor)
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/ServiceWorkerImpl.cpp
@@ -0,0 +1,65 @@
+/* -*- 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 "ServiceWorkerImpl.h"
+
+namespace mozilla {
+namespace dom {
+
+ServiceWorkerImpl::~ServiceWorkerImpl()
+{
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
+  mInfo->RemoveListener(this);
+}
+
+void
+ServiceWorkerImpl::AddServiceWorker(ServiceWorker* aWorker)
+{
+  MOZ_DIAGNOSTIC_ASSERT(!mOuter);
+  MOZ_DIAGNOSTIC_ASSERT(aWorker);
+  mOuter = aWorker;
+
+  // Wait to attach to the info as a listener until we have the outer
+  // set.  This is important because the info will try to set the
+  // state immediately.
+  mInfo->AddListener(this);
+}
+
+void
+ServiceWorkerImpl::RemoveServiceWorker(ServiceWorker* aWorker)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mOuter);
+  MOZ_DIAGNOSTIC_ASSERT(mOuter == aWorker);
+  mOuter = nullptr;
+}
+
+void
+ServiceWorkerImpl::PostMessage(ipc::StructuredCloneData&& aData,
+                               const ClientInfo& aClientInfo,
+                               const ClientState& aClientState)
+{
+  mInfo->PostMessage(Move(aData), aClientInfo, aClientState);
+}
+
+void
+ServiceWorkerImpl::SetState(ServiceWorkerState aState)
+{
+  if (!mOuter) {
+    return;
+  }
+  mOuter->SetState(aState);
+}
+
+
+ServiceWorkerImpl::ServiceWorkerImpl(ServiceWorkerInfo* aInfo)
+  : mInfo(aInfo)
+  , mOuter(nullptr)
+{
+  MOZ_DIAGNOSTIC_ASSERT(mInfo);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/serviceworkers/ServiceWorkerImpl.h
@@ -0,0 +1,51 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_ServiceWorkerImpl_h
+#define mozilla_dom_ServiceWorkerImpl_h
+
+#include "ServiceWorker.h"
+#include "ServiceWorkerInfo.h"
+
+namespace mozilla {
+namespace dom {
+
+class ServiceWorkerInfo;
+
+class ServiceWorkerImpl final : public ServiceWorker::Inner
+                              , public ServiceWorkerInfo::Listener
+{
+  RefPtr<ServiceWorkerInfo> mInfo;
+  ServiceWorker* mOuter;
+
+  ~ServiceWorkerImpl();
+
+  // ServiceWorker::Inner interface
+  void
+  AddServiceWorker(ServiceWorker* aWorker) override;
+
+  void
+  RemoveServiceWorker(ServiceWorker* aWorker) override;
+
+  void
+  PostMessage(ipc::StructuredCloneData&& aData,
+              const ClientInfo& aClientInfo,
+              const ClientState& aClientState) override;
+
+  // ServiceWorkerInfo::Listener interface
+  void
+  SetState(ServiceWorkerState aState) override;
+
+public:
+  explicit ServiceWorkerImpl(ServiceWorkerInfo* aInfo);
+
+  NS_INLINE_DECL_REFCOUNTING(ServiceWorkerImpl, override);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ServiceWorkerImpl_h
--- a/dom/serviceworkers/ServiceWorkerInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerInfo.cpp
@@ -113,17 +113,17 @@ ServiceWorkerInfo::DetachDebugger()
   return mServiceWorkerPrivate->DetachDebugger();
 }
 
 namespace {
 
 class ChangeStateUpdater final : public Runnable
 {
 public:
-  ChangeStateUpdater(const nsTArray<ServiceWorker*>& aInstances,
+  ChangeStateUpdater(const nsTArray<ServiceWorkerInfo::Listener*>& aInstances,
                      ServiceWorkerState aState)
     : Runnable("dom::ChangeStateUpdater")
     , mState(aState)
   {
     for (size_t i = 0; i < aInstances.Length(); ++i) {
       mInstances.AppendElement(aInstances[i]);
     }
   }
@@ -132,17 +132,17 @@ public:
   {
     for (size_t i = 0; i < mInstances.Length(); ++i) {
       mInstances[i]->SetState(mState);
     }
     return NS_OK;
   }
 
 private:
-  AutoTArray<RefPtr<ServiceWorker>, 1> mInstances;
+  AutoTArray<RefPtr<ServiceWorkerInfo::Listener>, 1> mInstances;
   ServiceWorkerState mState;
 };
 
 }
 
 void
 ServiceWorkerInfo::UpdateState(ServiceWorkerState aState)
 {
@@ -220,43 +220,30 @@ static uint64_t gServiceWorkerInfoCurren
 
 uint64_t
 ServiceWorkerInfo::GetNextID() const
 {
   return ++gServiceWorkerInfoCurrentID;
 }
 
 void
-ServiceWorkerInfo::AddServiceWorker(ServiceWorker* aWorker)
+ServiceWorkerInfo::AddListener(Listener* aListener)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aWorker);
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-  nsAutoString workerURL;
-  aWorker->GetScriptURL(workerURL);
-  MOZ_DIAGNOSTIC_ASSERT(
-    workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
-#endif
-  MOZ_ASSERT(!mInstances.Contains(aWorker));
+  MOZ_DIAGNOSTIC_ASSERT(aListener);
+  MOZ_ASSERT(!mInstances.Contains(aListener));
 
-  mInstances.AppendElement(aWorker);
-  aWorker->SetState(State());
+  mInstances.AppendElement(aListener);
+  aListener->SetState(State());
 }
 
 void
-ServiceWorkerInfo::RemoveServiceWorker(ServiceWorker* aWorker)
+ServiceWorkerInfo::RemoveListener(Listener* aListener)
 {
-  MOZ_DIAGNOSTIC_ASSERT(aWorker);
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-  nsAutoString workerURL;
-  aWorker->GetScriptURL(workerURL);
-  MOZ_DIAGNOSTIC_ASSERT(
-    workerURL.Equals(NS_ConvertUTF8toUTF16(mDescriptor.ScriptURL())));
-#endif
-
-  DebugOnly<bool> removed = mInstances.RemoveElement(aWorker);
+  MOZ_DIAGNOSTIC_ASSERT(aListener);
+  DebugOnly<bool> removed = mInstances.RemoveElement(aListener);
   MOZ_ASSERT(removed);
 }
 
 void
 ServiceWorkerInfo::PostMessage(ipc::StructuredCloneData&& aData,
                                const ClientInfo& aClientInfo,
                                const ClientState& aClientState)
 {
--- a/dom/serviceworkers/ServiceWorkerInfo.h
+++ b/dom/serviceworkers/ServiceWorkerInfo.h
@@ -7,33 +7,41 @@
 #ifndef mozilla_dom_serviceworkerinfo_h
 #define mozilla_dom_serviceworkerinfo_h
 
 #include "MainThreadUtils.h"
 #include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/OriginAttributes.h"
 #include "nsIServiceWorkerManager.h"
-#include "ServiceWorker.h"
 
 namespace mozilla {
 namespace dom {
 
 class ClientInfoAndState;
 class ServiceWorkerPrivate;
 
 /*
  * Wherever the spec treats a worker instance and a description of said worker
  * as the same thing; i.e. "Resolve foo with
  * _GetNewestWorker(serviceWorkerRegistration)", we represent the description
  * by this class and spawn a ServiceWorker in the right global when required.
  */
 class ServiceWorkerInfo final : public nsIServiceWorkerInfo
-                              , public ServiceWorker::Inner
 {
+public:
+  class Listener
+  {
+  public:
+    virtual void
+    SetState(ServiceWorkerState aState) = 0;
+
+    NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
+  };
+
 private:
   nsCOMPtr<nsIPrincipal> mPrincipal;
   ServiceWorkerDescriptor mDescriptor;
   const nsString mCacheName;
   OriginAttributes mOriginAttributes;
 
   // This LoadFlags is only applied to imported scripts, since the main script
   // has already been downloaded when performing the bytecheck. This LoadFlag is
@@ -55,17 +63,17 @@ private:
   PRTime mActivatedTime;
   PRTime mRedundantTime;
 
   // We hold rawptrs since the ServiceWorker constructor and destructor ensure
   // addition and removal.
   //
   // There is a high chance of there being at least one ServiceWorker
   // associated with this all the time.
-  AutoTArray<ServiceWorker*, 1> mInstances;
+  AutoTArray<Listener*, 1> mInstances;
 
   RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
   bool mSkipWaitingFlag;
 
   enum {
     Unknown,
     Enabled,
     Disabled
@@ -73,32 +81,31 @@ private:
 
   ~ServiceWorkerInfo();
 
   // Generates a unique id for the service worker, with zero being treated as
   // invalid.
   uint64_t
   GetNextID() const;
 
-  // ServiceWorker::Inner implementation
-  virtual void
-  AddServiceWorker(ServiceWorker* aWorker) override;
-
-  virtual void
-  RemoveServiceWorker(ServiceWorker* aWorker) override;
-
-  virtual void
-  PostMessage(ipc::StructuredCloneData&& aData,
-              const ClientInfo& aClientInfo,
-              const ClientState& aClientState) override;
-
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISERVICEWORKERINFO
 
+  void
+  AddListener(Listener* aListener);
+
+  void
+  RemoveListener(Listener* aListener);
+
+  void
+  PostMessage(ipc::StructuredCloneData&& aData,
+              const ClientInfo& aClientInfo,
+              const ClientState& aClientState);
+
   class ServiceWorkerPrivate*
   WorkerPrivate() const
   {
     MOZ_ASSERT(mServiceWorkerPrivate);
     return mServiceWorkerPrivate;
   }
 
   nsIPrincipal*
--- a/dom/serviceworkers/ServiceWorkerRegistrar.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrar.cpp
@@ -10,16 +10,17 @@
 #include "mozilla/net/MozURL.h"
 
 #include "nsIEventTarget.h"
 #include "nsIInputStream.h"
 #include "nsILineInputStream.h"
 #include "nsIObserverService.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
+#include "nsIServiceWorkerManager.h"
 
 #include "MainThreadUtils.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/CycleCollectedJSContext.h"
 #include "mozilla/dom/StorageActivityService.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
@@ -31,16 +32,17 @@
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsContentUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
+#include "ServiceWorkerUtils.h"
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
--- a/dom/serviceworkers/moz.build
+++ b/dom/serviceworkers/moz.build
@@ -27,16 +27,17 @@ EXPORTS.mozilla.dom += [
 ]
 
 UNIFIED_SOURCES += [
     'ServiceWorker.cpp',
     'ServiceWorkerContainer.cpp',
     'ServiceWorkerContainerImpl.cpp',
     'ServiceWorkerDescriptor.cpp',
     'ServiceWorkerEvents.cpp',
+    'ServiceWorkerImpl.cpp',
     'ServiceWorkerInfo.cpp',
     'ServiceWorkerInterceptController.cpp',
     'ServiceWorkerJob.cpp',
     'ServiceWorkerJobQueue.cpp',
     'ServiceWorkerManager.cpp',
     'ServiceWorkerManagerChild.cpp',
     'ServiceWorkerManagerParent.cpp',
     'ServiceWorkerManagerService.cpp',
--- a/dom/tests/mochitest/general/test_consoleAPI.html
+++ b/dom/tests/mochitest/general/test_consoleAPI.html
@@ -27,16 +27,17 @@ function doTest() {
     "exception": "function",
     "debug": "function",
     "trace": "function",
     "dir": "function",
     "group": "function",
     "groupCollapsed": "function",
     "groupEnd": "function",
     "time": "function",
+    "timeLog": "function",
     "timeEnd": "function",
     "profile": "function",
     "profileEnd": "function",
     "assert": "function",
     "count": "function",
     "table": "function",
     "clear": "function",
     "dirxml": "function",
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -252,38 +252,32 @@ var interfaceNamesInGlobalScope =
     {name: "CSSMediaRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSMozDocumentRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSNamespaceRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSPageRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "CSSPrimitiveValue", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSPseudoElement", insecureContext: true, release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSRuleList", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSStyleDeclaration", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSStyleRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSStyleSheet", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSSupportsRule", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CSSTransition", insecureContext: true, release: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "CSSValue", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "CSSValueList", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CustomElementRegistry", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "CustomEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "DataTransfer", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "DataTransferItem", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
@@ -810,24 +804,20 @@ var interfaceNamesInGlobalScope =
     {name: "PushSubscription", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "PushSubscriptionOptions", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RadioNodeList", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Range", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "Rect", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Request", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Response", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "RGBColor", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RTCCertificate", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RTCDataChannel", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RTCDataChannelEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "RTCDTMFSender", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
deleted file mode 100644
--- a/dom/webidl/CSSPrimitiveValue.webidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-interface CSSPrimitiveValue : CSSValue {
-
-  // UnitTypes
-  const unsigned short      CSS_UNKNOWN                    = 0;
-  const unsigned short      CSS_NUMBER                     = 1;
-  const unsigned short      CSS_PERCENTAGE                 = 2;
-  const unsigned short      CSS_EMS                        = 3;
-  const unsigned short      CSS_EXS                        = 4;
-  const unsigned short      CSS_PX                         = 5;
-  const unsigned short      CSS_CM                         = 6;
-  const unsigned short      CSS_MM                         = 7;
-  const unsigned short      CSS_IN                         = 8;
-  const unsigned short      CSS_PT                         = 9;
-  const unsigned short      CSS_PC                         = 10;
-  const unsigned short      CSS_DEG                        = 11;
-  const unsigned short      CSS_RAD                        = 12;
-  const unsigned short      CSS_GRAD                       = 13;
-  const unsigned short      CSS_MS                         = 14;
-  const unsigned short      CSS_S                          = 15;
-  const unsigned short      CSS_HZ                         = 16;
-  const unsigned short      CSS_KHZ                        = 17;
-  const unsigned short      CSS_DIMENSION                  = 18;
-  const unsigned short      CSS_STRING                     = 19;
-  const unsigned short      CSS_URI                        = 20;
-  const unsigned short      CSS_IDENT                      = 21;
-  const unsigned short      CSS_ATTR                       = 22;
-  const unsigned short      CSS_COUNTER                    = 23;
-  const unsigned short      CSS_RECT                       = 24;
-  const unsigned short      CSS_RGBCOLOR                   = 25;
-
-  readonly attribute unsigned short   primitiveType;
-  [Throws]
-  void               setFloatValue(unsigned short unitType,
-                                   float floatValue);
-  [Throws]
-  float              getFloatValue(unsigned short unitType);
-  [Throws]
-  void               setStringValue(unsigned short stringType,
-                                    DOMString stringValue);
-  [Throws]
-  DOMString          getStringValue();
-  [Throws]
-  void               getCounterValue();  // always throws
-  [Throws]
-  Rect               getRectValue();
-  [Throws]
-  RGBColor           getRGBColorValue();
-};
deleted file mode 100644
--- a/dom/webidl/CSSValue.webidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-interface CSSValue {
-
-  // UnitTypes
-  const unsigned short      CSS_INHERIT                    = 0;
-  const unsigned short      CSS_PRIMITIVE_VALUE            = 1;
-  const unsigned short      CSS_VALUE_LIST                 = 2;
-  const unsigned short      CSS_CUSTOM                     = 3;
-
-           [Throws]
-           attribute DOMString        cssText;
-
-  readonly attribute unsigned short   cssValueType;
-};
deleted file mode 100644
--- a/dom/webidl/CSSValueList.webidl
+++ /dev/null
@@ -1,10 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-interface CSSValueList : CSSValue {
-         readonly attribute unsigned long    length;
-  getter CSSValue?          item(unsigned long index);
-};
--- a/dom/webidl/Console.webidl
+++ b/dom/webidl/Console.webidl
@@ -49,16 +49,18 @@ namespace console {
   void groupCollapsed(any... data);
   [UseCounter]
   void groupEnd();
 
   // Timing
   [UseCounter]
   void time(optional DOMString label = "default");
   [UseCounter]
+  void timeLog(optional DOMString label = "default", any... data);
+  [UseCounter]
   void timeEnd(optional DOMString label = "default");
 
   // Mozilla only or Webcompat methods
 
   [UseCounter]
   void _exception(any... data);
   [UseCounter]
   void timeStamp(optional any data);
@@ -116,17 +118,17 @@ dictionary ConsoleStackEntry {
   DOMString functionName = "";
   DOMString? asyncCause;
 };
 
 dictionary ConsoleTimerStart {
   DOMString name = "";
 };
 
-dictionary ConsoleTimerEnd {
+dictionary ConsoleTimerLogOrEnd {
   DOMString name = "";
   double duration = 0;
 };
 
 dictionary ConsoleTimerError {
   DOMString error = "";
   DOMString name = "";
 };
@@ -160,32 +162,34 @@ interface ConsoleInstance {
 
   // Grouping
   void group(any... data);
   void groupCollapsed(any... data);
   void groupEnd();
 
   // Timing
   void time(optional DOMString label = "default");
+  void timeLog(optional DOMString label = "default", any... data);
   void timeEnd(optional DOMString label = "default");
 
   // Mozilla only or Webcompat methods
 
   void _exception(any... data);
   void timeStamp(optional any data);
 
   void profile(any... data);
   void profileEnd(any... data);
 };
 
 callback ConsoleInstanceDumpCallback = void (DOMString message);
 
 enum ConsoleLogLevel {
-  "All", "Debug", "Log", "Info", "Clear", "Trace", "TimeEnd", "Time", "Group",
-  "GroupEnd", "Profile", "ProfileEnd", "Dir", "Dirxml", "Warn", "Error", "Off"
+  "All", "Debug", "Log", "Info", "Clear", "Trace", "TimeLog", "TimeEnd", "Time",
+  "Group", "GroupEnd", "Profile", "ProfileEnd", "Dir", "Dirxml", "Warn", "Error",
+  "Off"
 };
 
 dictionary ConsoleInstanceOptions {
   // An optional function to intercept all strings written to stdout.
   ConsoleInstanceDumpCallback dump;
 
   // An optional prefix string to be printed before the actual logged message.
   DOMString prefix = "";
deleted file mode 100644
--- a/dom/webidl/RGBColor.webidl
+++ /dev/null
@@ -1,17 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * The origin of this IDL file is
- * http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-RGBColor
- */
-
-interface RGBColor {
-  readonly attribute CSSPrimitiveValue  red;
-  readonly attribute CSSPrimitiveValue  green;
-  readonly attribute CSSPrimitiveValue  blue;
-
-  // mozilla specific
-  readonly attribute CSSPrimitiveValue alpha;
-};
deleted file mode 100644
--- a/dom/webidl/Rect.webidl
+++ /dev/null
@@ -1,12 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-interface Rect {
-  readonly attribute CSSPrimitiveValue top;
-  readonly attribute CSSPrimitiveValue right;
-  readonly attribute CSSPrimitiveValue bottom;
-  readonly attribute CSSPrimitiveValue left;
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -436,27 +436,24 @@ WEBIDL_FILES = [
     'CSSImportRule.webidl',
     'CSSKeyframeRule.webidl',
     'CSSKeyframesRule.webidl',
     'CSSLexer.webidl',
     'CSSMediaRule.webidl',
     'CSSMozDocumentRule.webidl',
     'CSSNamespaceRule.webidl',
     'CSSPageRule.webidl',
-    'CSSPrimitiveValue.webidl',
     'CSSPseudoElement.webidl',
     'CSSRule.webidl',
     'CSSRuleList.webidl',
     'CSSStyleDeclaration.webidl',
     'CSSStyleRule.webidl',
     'CSSStyleSheet.webidl',
     'CSSSupportsRule.webidl',
     'CSSTransition.webidl',
-    'CSSValue.webidl',
-    'CSSValueList.webidl',
     'CustomElementRegistry.webidl',
     'DataTransfer.webidl',
     'DataTransferItem.webidl',
     'DataTransferItemList.webidl',
     'DecoderDoctorNotification.webidl',
     'DedicatedWorkerGlobalScope.webidl',
     'DelayNode.webidl',
     'DeviceMotionEvent.webidl',
@@ -733,20 +730,18 @@ WEBIDL_FILES = [
     'PushEvent.webidl',
     'PushManager.webidl',
     'PushManager.webidl',
     'PushMessageData.webidl',
     'PushSubscription.webidl',
     'PushSubscriptionOptions.webidl',
     'RadioNodeList.webidl',
     'Range.webidl',
-    'Rect.webidl',
     'Request.webidl',
     'Response.webidl',
-    'RGBColor.webidl',
     'RTCStatsReport.webidl',
     'Screen.webidl',
     'ScreenOrientation.webidl',
     'ScriptProcessorNode.webidl',
     'ScrollAreaEvent.webidl',
     'ScrollBoxObject.webidl',
     'Selection.webidl',
     'ServiceWorker.webidl',
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp
+++ b/editor/libeditor/HTMLAbsPositionEditor.cpp
@@ -9,17 +9,16 @@
 #include "HTMLEditorObjectResizerUtils.h"
 #include "HTMLEditRules.h"
 #include "HTMLEditUtils.h"
 #include "TextEditUtils.h"
 #include "mozilla/EditAction.h"
 #include "mozilla/EditorUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/TextEditRules.h"
-#include "mozilla/dom/CSSPrimitiveValueBinding.h"
 #include "mozilla/dom/Selection.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsAlgorithm.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
--- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp
+++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp
@@ -1,16 +1,15 @@
 /* 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/HTMLEditor.h"
 
 #include "mozilla/Attributes.h"
-#include "mozilla/dom/CSSPrimitiveValueBinding.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/mozalloc.h"
 #include "nsAString.h"
 #include "nsCOMPtr.h"
 #include "nsComputedDOMStyle.h"
 #include "nsDebug.h"
 #include "nsError.h"
--- a/gfx/thebes/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -4206,25 +4206,26 @@ gfxFontStyle::gfxFontStyle(FontSlantStyl
         NS_WARNING("null language");
         language = nsGkAtoms::x_western;
     }
 }
 
 PLDHashNumber
 gfxFontStyle::Hash() const
 {
-    return mozilla::HashGeneric(systemFont, style.ForHash(),
-                                stretch.ForHash(), weight.ForHash(),
-                                size, sizeAdjust,
-                                nsRefPtrHashKey<nsAtom>::HashKey(language));
-    /* XXX
-    return (style + (systemFont << 7) + (weight.ForHash() << 8) +
-            uint32_t(size*1000) + int32_t(sizeAdjust*1000)) ^
-            nsRefPtrHashKey<nsAtom>::HashKey(language);
-    */
+    uint32_t hash =
+        variationSettings.IsEmpty()
+            ? 0
+            : mozilla::HashBytes(variationSettings.Elements(),
+                                 variationSettings.Length() *
+                                     sizeof(gfxFontVariation));
+    return mozilla::AddToHash(hash, systemFont, style.ForHash(),
+                              stretch.ForHash(), weight.ForHash(),
+                              size, int32_t(sizeAdjust * 1000.0f),
+                              nsRefPtrHashKey<nsAtom>::HashKey(language));
 }
 
 void
 gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel)
 {
     MOZ_ASSERT(variantSubSuper != NS_FONT_VARIANT_POSITION_NORMAL &&
                baselineOffset == 0,
                "can't adjust this style for sub/superscript");
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -1519,18 +1519,16 @@ WeightDistance(const gfxFontEntry* aFont
         if (distance < 0.0) {
             distance = kReverseDistance - distance;
         }
         distance += addedDistance;
     }
     return distance;
 }
 
-#define MAX_DISTANCE 1.0e20 // >> than any WeightStyleStretchDistance result
-
 static inline double
 WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
                            const gfxFontStyle& aTargetStyle)
 {
     double stretchDist = StretchDistance(aFontEntry, aTargetStyle.stretch);
     double styleDist = StyleDistance(aFontEntry, aTargetStyle.style);
     double weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
 
@@ -1620,17 +1618,17 @@ gfxFontFamily::FindAllFontsForStyle(cons
     // given but the 99% use case is only a single font entry per
     // weight/style/stretch distance value. To optimize this, only add entries
     // to the matched font array when another entry already has the same
     // weight/style/stretch distance and add the last matched font entry. For
     // normal platform fonts with a single font entry for each
     // weight/style/stretch combination, only the last matched font entry will
     // be added.
 
-    double minDistance = MAX_DISTANCE;
+    double minDistance = INFINITY;
     gfxFontEntry* matched = nullptr;
     // iterate in forward order so that faces like 'Bold' are matched before
     // matching style distance faces such as 'Bold Outline' (see bug 1185812)
     for (uint32_t i = 0; i < count; i++) {
         fe = mAvailableFonts[i];
         // weight/style/stretch priority: stretch >> style >> weight
         double distance = WeightStyleStretchDistance(fe, aFontStyle);
         if (distance < minDistance) {
@@ -1730,137 +1728,91 @@ gfxFontFamily::ContainsFace(gfxFontEntry
 #endif
 
 void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     // just return the primary name; subclasses should override
     aLocalizedName = mName;
 }
 
-// metric for how close a given font matches a style
-static float
-CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
-{
-    float rank = 0;
-    if (aStyle) {
-        // TODO: stretch
-
-        // italics
-        bool wantUpright = aStyle->style.IsNormal();
-        if (aFontEntry->IsUpright() == wantUpright) {
-            rank += 5000.0f;
-        }
-
-        // measure of closeness of weight to the desired value
-        if (aFontEntry->Weight().Min() > aStyle->weight) {
-            rank += 1000.0f - (aFontEntry->Weight().Min() - aStyle->weight);
-        } else if (aFontEntry->Weight().Max() < aStyle->weight) {
-            rank += 1000.0f - (aStyle->weight - aFontEntry->Weight().Max());
-        } else {
-            rank += 2000.0f; // the font supports the exact weight wanted
-        }
-    } else {
-        // if no font to match, prefer non-bold, non-italic fonts
-        if (aFontEntry->IsUpright()) {
-            rank += 2000.0f;
-        }
-        if (aFontEntry->Weight().Min() <= FontWeight(500)) {
-            rank += 1000.0f;
-        }
-    }
-
-    return rank;
-}
-
-#define RANK_MATCHED_CMAP   10000.0f
-
 void
-gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
+gfxFontFamily::FindFontForChar(GlobalFontMatch* aMatchData)
 {
     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
         // none of the faces in the family support the required char,
         // so bail out immediately
         return;
     }
 
-    gfxFontEntry *fe =
-        FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
-                                            : gfxFontStyle(),
-                         true);
+    gfxFontEntry* fe =
+        FindFontForStyle(aMatchData->mStyle, /*aIgnoreSizeTolerance*/ true);
+    if (!fe || fe->SkipDuringSystemFallback()) {
+        return;
+    }
 
-    if (fe && !fe->SkipDuringSystemFallback()) {
-        float rank = 0;
+    float distance = INFINITY;
 
-        if (fe->HasCharacter(aMatchData->mCh)) {
-            rank += RANK_MATCHED_CMAP;
-            aMatchData->mCount++;
-
-            LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
+    if (fe->HasCharacter(aMatchData->mCh)) {
+        aMatchData->mCount++;
 
-            if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
-                uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
-                Script script = GetScriptCode(aMatchData->mCh);
-                MOZ_LOG(log, LogLevel::Debug,\
-                       ("(textrun-systemfallback-fonts) char: u+%6.6x "
-                        "unicode-range: %d script: %d match: [%s]\n",
-                        aMatchData->mCh,
-                        unicodeRange, int(script),
-                        NS_ConvertUTF16toUTF8(fe->Name()).get()));
-            }
+        LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
 
-            // omitting from original windows code -- family name, lang group, pitch
-            // not available in current FontEntry implementation
-            rank += CalcStyleMatch(fe, aMatchData->mStyle);
-        } else if (!fe->IsNormalStyle()) {
-            // If style/weight/stretch was not Normal, see if we can
-            // fall back to a next-best face (e.g. Arial Black -> Bold,
-            // or Arial Narrow -> Regular).
-            GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
-            SearchAllFontsForChar(&data);
-            if (data.mMatchRank >= RANK_MATCHED_CMAP) {
-                fe = data.mBestMatch;
-                rank = data.mMatchRank;
-            } else {
-                return;
-            }
-        } else {
-            return;
+        if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
+            uint32_t unicodeRange = FindCharUnicodeRange(aMatchData->mCh);
+            Script script = GetScriptCode(aMatchData->mCh);
+            MOZ_LOG(log, LogLevel::Debug,\
+                   ("(textrun-systemfallback-fonts) char: u+%6.6x "
+                    "unicode-range: %d script: %d match: [%s]\n",
+                    aMatchData->mCh,
+                    unicodeRange, int(script),
+                    NS_ConvertUTF16toUTF8(fe->Name()).get()));
         }
 
-        aMatchData->mCmapsTested++;
-
-        // xxx - add whether AAT font with morphing info for specific lang groups
+        distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
+    } else if (!fe->IsNormalStyle()) {
+        // If style/weight/stretch was not Normal, see if we can
+        // fall back to a next-best face (e.g. Arial Black -> Bold,
+        // or Arial Narrow -> Regular).
+        GlobalFontMatch data(aMatchData->mCh, aMatchData->mStyle);
+        SearchAllFontsForChar(&data);
+        if (std::isfinite(data.mMatchDistance)) {
+            fe = data.mBestMatch;
+            distance = data.mMatchDistance;
+        }
+    }
+    aMatchData->mCmapsTested++;
 
-        if (rank > aMatchData->mMatchRank
-            || (rank == aMatchData->mMatchRank &&
-                Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
-        {
-            aMatchData->mBestMatch = fe;
-            aMatchData->mMatchedFamily = this;
-            aMatchData->mMatchRank = rank;
-        }
+    if (std::isinf(distance)) {
+        return;
+    }
+
+    if (distance < aMatchData->mMatchDistance ||
+        (distance == aMatchData->mMatchDistance &&
+         Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0)) {
+        aMatchData->mBestMatch = fe;
+        aMatchData->mMatchedFamily = this;
+        aMatchData->mMatchDistance = distance;
     }
 }
 
 void
-gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
+gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch* aMatchData)
 {
     uint32_t i, numFonts = mAvailableFonts.Length();
     for (i = 0; i < numFonts; i++) {
         gfxFontEntry *fe = mAvailableFonts[i];
         if (fe && fe->HasCharacter(aMatchData->mCh)) {
-            float rank = RANK_MATCHED_CMAP;
-            rank += CalcStyleMatch(fe, aMatchData->mStyle);
-            if (rank > aMatchData->mMatchRank
-                || (rank == aMatchData->mMatchRank &&
+            float distance = WeightStyleStretchDistance(fe, aMatchData->mStyle);
+            if (distance < aMatchData->mMatchDistance
+                || (distance == aMatchData->mMatchDistance &&
                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
             {
                 aMatchData->mBestMatch = fe;
                 aMatchData->mMatchedFamily = this;
-                aMatchData->mMatchRank = rank;
+                aMatchData->mMatchDistance = distance;
             }
         }
     }
 }
 
 /*virtual*/
 gfxFontFamily::~gfxFontFamily()
 {
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -19,16 +19,17 @@
 #include "MainThreadUtils.h"
 #include "nsUnicodeScriptCodes.h"
 #include "nsDataHashtable.h"
 #include "harfbuzz/hb.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/WeakPtr.h"
+#include <math.h>
 
 typedef struct gr_face gr_face;
 
 #ifdef DEBUG
 #include <stdio.h>
 #endif
 
 struct gfxFontStyle;
@@ -685,30 +686,29 @@ gfxFontEntry::SupportsBold()
            ((mRangeFlags & RangeFlags::eAutoWeight) ==
                RangeFlags::eAutoWeight &&
             HasBoldVariableWeight());
 }
 
 // used when iterating over all fonts looking for a match for a given character
 struct GlobalFontMatch {
     GlobalFontMatch(const uint32_t aCharacter,
-                    const gfxFontStyle *aStyle) :
-        mCh(aCharacter), mStyle(aStyle),
-        mMatchRank(0.0f), mCount(0), mCmapsTested(0)
+                    const gfxFontStyle& aStyle) :
+        mStyle(aStyle), mCh(aCharacter),
+        mCount(0), mCmapsTested(0), mMatchDistance(INFINITY)
         {
-
         }
 
+    RefPtr<gfxFontEntry>   mBestMatch;   // current best match
+    RefPtr<gfxFontFamily>  mMatchedFamily; // the family it belongs to
+    const gfxFontStyle&    mStyle;       // style to match
     const uint32_t         mCh;          // codepoint to be matched
-    const gfxFontStyle*    mStyle;       // style to match
-    float                  mMatchRank;   // metric indicating closest match
-    RefPtr<gfxFontEntry> mBestMatch;   // current best match
-    RefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
     uint32_t               mCount;       // number of fonts matched
     uint32_t               mCmapsTested; // number of cmaps tested
+    float                  mMatchDistance; // metric indicating closest match
 };
 
 class gfxFontFamily {
 public:
     // Used by stylo
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxFontFamily)
 
     explicit gfxFontFamily(const nsAString& aName) :
@@ -781,20 +781,20 @@ public:
 
     virtual void
     FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
                          nsTArray<gfxFontEntry*>& aFontEntryList,
                          bool aIgnoreSizeTolerance = false);
 
     // checks for a matching font within the family
     // used as part of the font fallback process
-    void FindFontForChar(GlobalFontMatch *aMatchData);
+    void FindFontForChar(GlobalFontMatch* aMatchData);
 
     // checks all fonts for a matching font within the family
-    void SearchAllFontsForChar(GlobalFontMatch *aMatchData);
+    void SearchAllFontsForChar(GlobalFontMatch* aMatchData);
 
     // read in other family names, if any, and use functor to add each into cache
     virtual void ReadOtherFamilyNames(gfxPlatformFontList *aPlatformFontList);
 
     // helper method for reading localized family names from the name table
     // of a single face
     static void ReadOtherFamilyNamesForFace(const nsAString& aFamilyName,
                                             const char *aNameData,
--- a/gfx/thebes/gfxMacFont.cpp
+++ b/gfx/thebes/gfxMacFont.cpp
@@ -18,16 +18,23 @@
 #include "gfxTextRun.h"
 #include "nsCocoaFeatures.h"
 
 #include "cairo-quartz.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
+template<class T>
+struct TagEquals {
+    bool Equals(const T& aIter, uint32_t aTag) const {
+        return aIter.mTag == aTag;
+    }
+};
+
 gfxMacFont::gfxMacFont(const RefPtr<UnscaledFontMac>& aUnscaledFont,
                        MacOSFontEntry *aFontEntry,
                        const gfxFontStyle *aFontStyle)
     : gfxFont(aUnscaledFont, aFontEntry, aFontStyle),
       mCGFont(nullptr),
       mCTFont(nullptr),
       mFontFace(nullptr),
       mFontSmoothingBackgroundColor(aFontStyle->fontSmoothingBackgroundColor),
@@ -42,16 +49,65 @@ gfxMacFont::gfxMacFont(const RefPtr<Unsc
             return;
         }
 
         // Get the variation settings needed to instantiate the fontEntry
         // for a particular fontStyle.
         AutoTArray<gfxFontVariation,4> vars;
         aFontEntry->GetVariationsForStyle(vars, *aFontStyle);
 
+        // Because of a Core Text bug, we need to ensure that if the font has
+        // an 'opsz' axis, it is always explicitly set, and NOT to the font's
+        // default value. (See bug 1457417.)
+        // We record the result of searching the font's axes in the font entry,
+        // so that this only has to be done by the first instance created for
+        // a given font resource.
+        const uint32_t kOpszTag = HB_TAG('o','p','s','z');
+
+        if (!aFontEntry->mCheckedForOpszAxis) {
+            aFontEntry->mCheckedForOpszAxis = true;
+            AutoTArray<gfxFontVariationAxis,4> axes;
+            aFontEntry->GetVariationAxes(axes);
+            auto index =
+                axes.IndexOf(kOpszTag, 0, TagEquals<gfxFontVariationAxis>());
+            if (index == axes.NoIndex) {
+                aFontEntry->mHasOpszAxis = false;
+            } else {
+                const auto& axis = axes[index];
+                aFontEntry->mHasOpszAxis = true;
+                aFontEntry->mOpszAxis = axis;
+                // Pick a slightly-adjusted version of the default that we'll
+                // use to work around Core Text's habit of ignoring any attempt
+                // to explicitly set the default value.
+                aFontEntry->mAdjustedDefaultOpsz =
+                    axis.mDefaultValue == axis.mMinValue
+                        ? axis.mDefaultValue + 0.001f
+                        : axis.mDefaultValue - 0.001f;
+            }
+        }
+
+        // Add 'opsz' if not present, or tweak its value if it looks too close
+        // to the default (after clamping to the font's available range).
+        if (aFontEntry->mHasOpszAxis) {
+            auto index =
+                vars.IndexOf(kOpszTag, 0, TagEquals<gfxFontVariation>());
+            if (index == vars.NoIndex) {
+                gfxFontVariation opsz{kOpszTag, aFontEntry->mAdjustedDefaultOpsz};
+                vars.AppendElement(opsz);
+            } else {
+                // Figure out a "safe" value that Core Text won't ignore.
+                auto& value = vars[index].mValue;
+                auto& axis = aFontEntry->mOpszAxis;
+                value = fmin(fmax(value, axis.mMinValue), axis.mMaxValue);
+                if (abs(value - axis.mDefaultValue) < 0.001f) {
+                    value = aFontEntry->mAdjustedDefaultOpsz;
+                }
+            }
+        }
+
         mCGFont =
             UnscaledFontMac::CreateCGFontWithVariations(baseFont,
                                                         vars.Length(),
                                                         vars.Elements());
         if (!mCGFont) {
           ::CFRetain(baseFont);
           mCGFont = baseFont;
         }
--- a/gfx/thebes/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -25,16 +25,17 @@
 
 class gfxMacPlatformFontList;
 
 // a single member of a font family (i.e. a single face, such as Times Italic)
 class MacOSFontEntry : public gfxFontEntry
 {
 public:
     friend class gfxMacPlatformFontList;
+    friend class gfxMacFont;
 
     MacOSFontEntry(const nsAString& aPostscriptName, WeightRange aWeight,
                    bool aIsStandardFace = false,
                    double aSizeHint = 0.0);
 
     // for use with data fonts
     MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
                    WeightRange aWeight, StretchRange aStretch, SlantStyleRange aStyle,
@@ -99,16 +100,29 @@ protected:
     bool mRequiresAAT;
     bool mIsCFF;
     bool mIsCFFInitialized;
     bool mHasVariations;
     bool mHasVariationsInitialized;
     bool mHasAATSmallCaps;
     bool mHasAATSmallCapsInitialized;
     bool mCheckedForTracking;
+
+    // To work around Core Text's mishandling of the default value for 'opsz',
+    // we need to record whether the font has an a optical size axis, what its
+    // range and default values are, and a usable close-to-default alternative.
+    // (See bug 1457417 for details.)
+    // These fields are used by gfxMacFont, but stored in the font entry so
+    // that only a single font instance needs to inspect the available
+    // variations.
+    bool mCheckedForOpszAxis;
+    bool mHasOpszAxis;
+    gfxFontVariationAxis mOpszAxis;
+    float mAdjustedDefaultOpsz;
+
     nsTHashtable<nsUint32HashKey> mAvailableTables;
 
     mozilla::ThreadSafeWeakPtr<mozilla::gfx::UnscaledFontMac> mUnscaledFont;
 
     // For AAT font being shaped by Core Text, a strong reference to the 'trak'
     // table (if present).
     hb_blob_t* mTrakTable;
     // Cached pointers to tables within 'trak', initialized by ParseTrakTable.
--- a/gfx/thebes/gfxMacPlatformFontList.mm
+++ b/gfx/thebes/gfxMacPlatformFontList.mm
@@ -376,16 +376,17 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mRequiresAAT(false),
       mIsCFF(false),
       mIsCFFInitialized(false),
       mHasVariations(false),
       mHasVariationsInitialized(false),
       mHasAATSmallCaps(false),
       mHasAATSmallCapsInitialized(false),
       mCheckedForTracking(false),
+      mCheckedForOpszAxis(false),
       mTrakTable(nullptr),
       mTrakValues(nullptr),
       mTrakSizeTable(nullptr)
 {
     mWeightRange = aWeight;
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
@@ -402,16 +403,17 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mRequiresAAT(false),
       mIsCFF(false),
       mIsCFFInitialized(false),
       mHasVariations(false),
       mHasVariationsInitialized(false),
       mHasAATSmallCaps(false),
       mHasAATSmallCapsInitialized(false),
       mCheckedForTracking(false),
+      mCheckedForOpszAxis(false),
       mTrakTable(nullptr),
       mTrakValues(nullptr),
       mTrakSizeTable(nullptr)
 {
     mFontRef = aFontRef;
     mFontRefInitialized = true;
     ::CFRetain(mFontRef);
 
--- a/gfx/thebes/gfxPlatformFontList.cpp
+++ b/gfx/thebes/gfxPlatformFontList.cpp
@@ -677,17 +677,17 @@ gfxPlatformFontList::CommonFontFallback(
                 return fontEntry;
             }
             // If we requested a styled font (bold and/or italic), and the char
             // was not available, check other faces of the family.
             if (!fontEntry->IsNormalStyle()) {
                 // If style/weight/stretch was not Normal, see if we can
                 // fall back to a next-best face (e.g. Arial Black -> Bold,
                 // or Arial Narrow -> Regular).
-                GlobalFontMatch data(aCh, aMatchStyle);
+                GlobalFontMatch data(aCh, *aMatchStyle);
                 fallback->SearchAllFontsForChar(&data);
                 if (data.mBestMatch) {
                     *aMatchedFamily = fallback;
                     return data.mBestMatch;
                 }
             }
         }
     }
@@ -710,17 +710,17 @@ gfxPlatformFontList::GlobalFontFallback(
             PlatformGlobalFontFallback(aCh, aRunScript, aMatchStyle,
                                        aMatchedFamily);
         if (fe) {
             return fe;
         }
     }
 
     // otherwise, try to find it among local fonts
-    GlobalFontMatch data(aCh, aMatchStyle);
+    GlobalFontMatch data(aCh, *aMatchStyle);
 
     // iterate over all font families to find a font that support the character
     for (auto iter = mFontFamilies.Iter(); !iter.Done(); iter.Next()) {
       RefPtr<gfxFontFamily>& family = iter.Data();
       // evaluate all fonts in this family for a match
       family->FindFontForChar(&data);
     }
 
@@ -1716,16 +1716,17 @@ gfxPlatformFontList::ClearLangGroupPrefF
          i < eFontPrefLang_First + eFontPrefLang_Count; i++) {
         auto& prefFontsLangGroup = mLangGroupPrefFonts[i];
         for (uint32_t j = eFamily_generic_first;
              j < eFamily_generic_first + eFamily_generic_count; j++) {
             prefFontsLangGroup[j] = nullptr;
         }
     }
     mCJKPrefLangs.Clear();
+    mEmojiPrefFont = nullptr;
 }
 
 // Support for memory reporting
 
 // this is also used by subclasses that hold additional font tables
 /*static*/ size_t
 gfxPlatformFontList::SizeOfFontFamilyTableExcludingThis(
     const FontFamilyTable& aTable,
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -2794,17 +2794,17 @@ gfxFontGroup::GetEllipsisTextRun(int32_t
     // fontgroup's life
     mCachedEllipsisTextRun->ReleaseFontGroup();
     return mCachedEllipsisTextRun.get();
 }
 
 gfxFont*
 gfxFontGroup::FindFallbackFaceForChar(gfxFontFamily* aFamily, uint32_t aCh)
 {
-    GlobalFontMatch data(aCh, &mStyle);
+    GlobalFontMatch data(aCh, mStyle);
     aFamily->SearchAllFontsForChar(&data);
     gfxFontEntry* fe = data.mBestMatch;
     if (!fe) {
         return nullptr;
     }
     return fe->FindOrMakeFont(&mStyle);
 }
 
--- a/js/src/builtin/Array.cpp
+++ b/js/src/builtin/Array.cpp
@@ -775,17 +775,19 @@ js::ArraySetLength(JSContext* cx, Handle
         // know in case that sparse indexed element is non-configurable, as
         // that element must prevent any deletions below it.  Bug 586842 should
         // fix this inefficiency by moving indexed storage to be entirely
         // separate from non-indexed storage.
         // A second reason for this optimization to be invalid is an active
         // for..in iteration over the array. Keys deleted before being reached
         // during the iteration must not be visited, and suppressing them here
         // would be too costly.
-        if (!arr->isIndexed() && !MaybeInIteration(arr, cx)) {
+        // This optimization is also invalid when there are sealed
+        // (non-configurable) elements.
+        if (!arr->isIndexed() && !MaybeInIteration(arr, cx) && !arr->denseElementsAreSealed()) {
             if (!arr->maybeCopyElementsForWrite(cx))
                 return false;
 
             uint32_t oldCapacity = arr->getDenseCapacity();
             uint32_t oldInitializedLength = arr->getDenseInitializedLength();
             MOZ_ASSERT(oldCapacity >= oldInitializedLength);
             if (oldInitializedLength > newLen)
                 arr->setDenseInitializedLength(newLen);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/non-extensible-elements7.js
@@ -0,0 +1,42 @@
+// Test array.length setter on non-extensible/sealed/frozen arrays.
+"use strict";
+
+load(libdir + "asserts.js");
+
+function testNonExtensible() {
+    var a = [1, 2, 3, , ,];
+    Object.preventExtensions(a);
+    for (var i = 0; i < 10; i++)
+        a.length = 10;
+    assertEq(a.length, 10);
+    for (var i = 0; i < 10; i++)
+        a.length = 0;
+    assertEq(a.length, 0);
+    assertEq(a.toString(), "");
+}
+testNonExtensible();
+
+function testSealed() {
+    var a = [1, 2, 3, , ,];
+    Object.seal(a);
+    for (var i = 0; i < 10; i++)
+        a.length = 10;
+    assertEq(a.length, 10);
+    for (var i = 0; i < 10; i++)
+        assertThrowsInstanceOf(() => a.length = 0, TypeError);
+    assertEq(a.length, 3);
+    assertEq(a.toString(), "1,2,3");
+}
+testSealed();
+
+function testFrozen() {
+    var a = [1, 2, 3, , ,];
+    Object.freeze(a);
+    for (var i = 0; i < 10; i++)
+        assertThrowsInstanceOf(() => a.length = 10, TypeError);
+    for (var i = 0; i < 10; i++)
+        assertThrowsInstanceOf(() => a.length = 0, TypeError);
+    assertEq(a.length, 5);
+    assertEq(a.toString(), "1,2,3,,");
+}
+testFrozen();
--- a/js/src/jit-test/tests/wasm/gc/anyref.js
+++ b/js/src/jit-test/tests/wasm/gc/anyref.js
@@ -145,21 +145,28 @@ assertEq(exports.ref_or_null(baguette, 0
 let ref = exports.ref_or_null(baguette, 1);
 assertEq(ref, baguette);
 assertEq(ref.calories, baguette.calories);
 
 ref = exports.nested(baguette, 0);
 assertEq(ref, baguette);
 assertEq(ref.calories, baguette.calories);
 
-if (wasmDebuggingIsSupported()) {
-    let g = newGlobal();
-    let dbg = new Debugger(g);
-    g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func (result anyref) (param anyref) get_local 0) (export "" 0))')));`);
-}
+// Make sure grow-memory isn't blocked by the lack of gc.
+(function() {
+    assertEq(wasmEvalText(`(module
+    (memory 0 64)
+    (func (export "f") (param anyref) (result i32)
+        i32.const 10
+        grow_memory
+        drop
+        current_memory
+    )
+)`).exports.f({}), 10);
+})();
 
 // More interesting use cases about control flow joins.
 
 function assertJoin(body) {
     let val = { i: -1 };
     assertEq(wasmEvalText(`(module
         (func (export "test") (param $ref anyref) (param $i i32) (result anyref)
             ${body}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/gc/debugger.js
@@ -0,0 +1,35 @@
+if (!wasmGcEnabled() || !wasmDebuggingIsSupported()) {
+    quit(0);
+}
+
+(function() {
+    let g = newGlobal();
+    let dbg = new Debugger(g);
+    g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func (result anyref) (param anyref) get_local 0) (export "" 0))')));`);
+})();
+
+(function() {
+    var g = newGlobal();
+    g.parent = this;
+
+    let src = `
+      (module
+        (func (export "func") (result anyref) (param $ref anyref)
+            get_local $ref
+        )
+      )
+    `;
+
+    g.eval(`
+        var obj = { somekey: 'somevalue' };
+
+        Debugger(parent).onEnterFrame = function(frame) {
+            let v = frame.environment.getVariable('var0');
+            assertEq(typeof v === 'object', true);
+            assertEq(typeof v.somekey === 'string', true);
+            assertEq(v.somekey === 'somevalue', true);
+        };
+
+        new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(\`${src}\`))).exports.func(obj);
+    `);
+})();
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -126,16 +126,18 @@ CacheRegisterAllocator::useFixedValueReg
 
     loc.setValueReg(reg);
     return reg;
 }
 
 Register
 CacheRegisterAllocator::useRegister(MacroAssembler& masm, TypedOperandId typedId)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     OperandLocation& loc = operandLocations_[typedId.id()];
     switch (loc.kind()) {
       case OperandLocation::PayloadReg:
         currentOpRegs_.add(loc.payloadReg());
         return loc.payloadReg();
 
       case OperandLocation::ValueReg: {
         // It's possible the value is still boxed: as an optimization, we unbox
@@ -201,16 +203,18 @@ CacheRegisterAllocator::useRegister(Macr
     }
 
     MOZ_CRASH();
 }
 
 ConstantOrRegister
 CacheRegisterAllocator::useConstantOrRegister(MacroAssembler& masm, ValOperandId val)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     OperandLocation& loc = operandLocations_[val.id()];
     switch (loc.kind()) {
       case OperandLocation::Constant:
         return loc.constant();
 
       case OperandLocation::PayloadReg:
       case OperandLocation::PayloadStack: {
         JSValueType payloadType = loc.payloadType();
@@ -231,27 +235,31 @@ CacheRegisterAllocator::useConstantOrReg
     }
 
     MOZ_CRASH();
 }
 
 Register
 CacheRegisterAllocator::defineRegister(MacroAssembler& masm, TypedOperandId typedId)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     OperandLocation& loc = operandLocations_[typedId.id()];
     MOZ_ASSERT(loc.kind() == OperandLocation::Uninitialized);
 
     Register reg = allocateRegister(masm);
     loc.setPayloadReg(reg, typedId.type());
     return reg;
 }
 
 ValueOperand
 CacheRegisterAllocator::defineValueRegister(MacroAssembler& masm, ValOperandId val)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     OperandLocation& loc = operandLocations_[val.id()];
     MOZ_ASSERT(loc.kind() == OperandLocation::Uninitialized);
 
     ValueOperand reg = allocateValueRegister(masm);
     loc.setValueReg(reg);
     return reg;
 }
 
@@ -304,16 +312,18 @@ CacheRegisterAllocator::discardStack(Mac
     }
     freePayloadSlots_.clear();
     freeValueSlots_.clear();
 }
 
 Register
 CacheRegisterAllocator::allocateRegister(MacroAssembler& masm)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     if (availableRegs_.empty())
         freeDeadOperandLocations(masm);
 
     if (availableRegs_.empty()) {
         // Still no registers available, try to spill unused operands to
         // the stack.
         for (size_t i = 0; i < operandLocations_.length(); i++) {
             OperandLocation& loc = operandLocations_[i];
@@ -354,16 +364,18 @@ CacheRegisterAllocator::allocateRegister
     Register reg = availableRegs_.takeAny();
     currentOpRegs_.add(reg);
     return reg;
 }
 
 void
 CacheRegisterAllocator::allocateFixedRegister(MacroAssembler& masm, Register reg)
 {
+    MOZ_ASSERT(!addedFailurePath_);
+
     // Fixed registers should be allocated first, to ensure they're
     // still available.
     MOZ_ASSERT(!currentOpRegs_.has(reg), "Register is in use");
 
     freeDeadOperandLocations(masm);
 
     if (availableRegs_.has(reg)) {
         availableRegs_.take(reg);
@@ -474,16 +486,20 @@ CacheRegisterAllocator::fixupAliasedInpu
                 spillOperandToStack(masm, &loc2);
             } else {
                 MOZ_ASSERT(loc1.kind() == OperandLocation::PayloadReg);
                 spillOperandToStack(masm, &loc1);
                 break; // Spilled loc1, so nothing else will alias it.
             }
         }
     }
+
+#ifdef DEBUG
+    assertValidState();
+#endif
 }
 
 GeneralRegisterSet
 CacheRegisterAllocator::inputRegisterSet() const
 {
     MOZ_ASSERT(origInputLocations_.length() == writer_.numInputOperands());
 
     AllocatableGeneralRegisterSet result;
@@ -663,16 +679,42 @@ CacheRegisterAllocator::popValue(MacroAs
         MOZ_ASSERT(loc->valueStack() < stackPushed_);
         masm.loadValue(Address(masm.getStackPointer(), stackPushed_ - loc->valueStack()), dest);
         masm.propagateOOM(freeValueSlots_.append(loc->valueStack()));
     }
 
     loc->setValueReg(dest);
 }
 
+#ifdef DEBUG
+void
+CacheRegisterAllocator::assertValidState() const
+{
+    // Assert different operands don't have aliasing storage. We depend on this
+    // when spilling registers, for instance.
+
+    if (!JitOptions.fullDebugChecks)
+        return;
+
+    for (size_t i = 0; i < operandLocations_.length(); i++) {
+        const auto& loc1 = operandLocations_[i];
+        if (loc1.isUninitialized())
+            continue;
+
+        for (size_t j = 0; j < i; j++) {
+            const auto& loc2 = operandLocations_[j];
+            if (loc2.isUninitialized())
+                continue;
+            MOZ_ASSERT(loc1 != loc2);
+            MOZ_ASSERT(!loc1.aliasesReg(loc2));
+        }
+    }
+}
+#endif
+
 bool
 OperandLocation::aliasesReg(const OperandLocation& other) const
 {
     MOZ_ASSERT(&other != this);
 
     switch (other.kind_) {
       case PayloadReg:
         return aliasesReg(other.payloadReg());
@@ -1160,16 +1202,20 @@ FailurePath::canShareFailurePath(const F
             return false;
     }
     return true;
 }
 
 bool
 CacheIRCompiler::addFailurePath(FailurePath** failure)
 {
+#ifdef DEBUG
+    allocator.setAddedFailurePath();
+#endif
+
     FailurePath newFailure;
     for (size_t i = 0; i < writer_.numInputOperands(); i++) {
         if (!newFailure.appendInput(allocator.operandLocation(i)))
             return false;
     }
     if (!newFailure.setSpilledRegs(allocator.spilledRegs()))
         return false;
     newFailure.setStackPushed(allocator.stackPushed());
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -206,16 +206,17 @@ class OperandLocation
         kind_ = Constant;
         data_.constant = v;
     }
     void setBaselineFrame(BaselineFrameSlot slot) {
         kind_ = BaselineFrame;
         data_.baselineFrameSlot = slot;
     }
 
+    bool isUninitialized() const { return kind_ == Uninitialized; }
     bool isInRegister() const { return kind_ == PayloadReg || kind_ == ValueReg; }
     bool isOnStack() const { return kind_ == PayloadStack || kind_ == ValueStack; }
 
     size_t stackPushed() const {
         if (kind_ == PayloadStack)
             return data_.payloadStack.stackPushed;
         MOZ_ASSERT(kind_ == ValueStack);
         return data_.valueStackPushed;
@@ -300,39 +301,52 @@ class MOZ_RAII CacheRegisterAllocator
     AllocatableGeneralRegisterSet availableRegsAfterSpill_;
 
     // Registers we took from availableRegsAfterSpill_ and spilled to the stack.
     SpilledRegisterVector spilledRegs_;
 
     // The number of bytes pushed on the native stack.
     uint32_t stackPushed_;
 
+#ifdef DEBUG
+    // Flag used to assert individual CacheIR instructions don't allocate
+    // registers after calling addFailurePath.
+    bool addedFailurePath_;
+#endif
+
     // The index of the CacheIR instruction we're currently emitting.
     uint32_t currentInstruction_;
 
     const CacheIRWriter& writer_;
 
     CacheRegisterAllocator(const CacheRegisterAllocator&) = delete;
     CacheRegisterAllocator& operator=(const CacheRegisterAllocator&) = delete;
 
     void freeDeadOperandLocations(MacroAssembler& masm);
 
     void spillOperandToStack(MacroAssembler& masm, OperandLocation* loc);
     void spillOperandToStackOrRegister(MacroAssembler& masm, OperandLocation* loc);
 
     void popPayload(MacroAssembler& masm, OperandLocation* loc, Register dest);
     void popValue(MacroAssembler& masm, OperandLocation* loc, ValueOperand dest);
 
+#ifdef DEBUG
+    void assertValidState() const;
+#endif
+
   public:
     friend class AutoScratchRegister;
     friend class AutoScratchRegisterExcluding;
 
     explicit CacheRegisterAllocator(const CacheIRWriter& writer)
       : allocatableRegs_(GeneralRegisterSet::All()),
         stackPushed_(0),
+#ifdef DEBUG
+        addedFailurePath_(false),
+#endif
         currentInstruction_(0),
         writer_(writer)
     {}
 
     MOZ_MUST_USE bool init();
 
     void initAvailableRegs(const AllocatableGeneralRegisterSet& available) {
         availableRegs_ = available;
@@ -378,20 +392,31 @@ class MOZ_RAII CacheRegisterAllocator
     const SpilledRegisterVector& spilledRegs() const { return spilledRegs_; }
 
     MOZ_MUST_USE bool setSpilledRegs(const SpilledRegisterVector& regs) {
         spilledRegs_.clear();
         return spilledRegs_.appendAll(regs);
     }
 
     void nextOp() {
+#ifdef DEBUG
+        assertValidState();
+        addedFailurePath_ = false;
+#endif
         currentOpRegs_.clear();
         currentInstruction_++;
     }
 
+#ifdef DEBUG
+    void setAddedFailurePath() {
+        MOZ_ASSERT(!addedFailurePath_, "multiple failure paths for instruction");
+        addedFailurePath_ = true;
+    }
+#endif
+
     bool isDeadAfterInstruction(OperandId opId) const {
         return writer_.operandIsDead(opId.id(), currentInstruction_ + 1);
     }
 
     uint32_t stackPushed() const {
         return stackPushed_;
     }
     void setStackPushed(uint32_t pushed) {
@@ -531,25 +556,26 @@ class FailurePath
     // be emitted for two failure paths, so we can share them.
     bool canShareFailurePath(const FailurePath& other) const;
 };
 
 /**
  * Wrap an offset so that a call can decide to embed a constant
  * or load from the stub data.
  */
-class StubFieldOffset {
+class StubFieldOffset
+{
   private:
     uint32_t offset_;
     StubField::Type type_;
   public:
     StubFieldOffset(uint32_t offset, StubField::Type type)
       : offset_(offset),
         type_(type)
-      { }
+    { }
 
     uint32_t getOffset() { return offset_; }
     StubField::Type getStubFieldType() { return type_; }
 };
 
 class AutoOutputRegister;
 
 // Base class for BaselineCacheIRCompiler and IonCacheIRCompiler.
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -642,16 +642,19 @@ DebugFrame::getLocal(uint32_t localIndex
           vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
           break;
       case jit::MIRType::Float32:
           vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
           break;
       case jit::MIRType::Double:
           vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
           break;
+      case jit::MIRType::Pointer:
+          vp.set(ObjectOrNullValue(*(JSObject**)dataPtr));
+          break;
       default:
           MOZ_CRASH("local type");
     }
     return true;
 }
 
 void
 DebugFrame::updateReturnJSValue()
@@ -670,16 +673,19 @@ DebugFrame::updateReturnJSValue()
           cachedReturnJSValue_.setDouble((double)resultI64_);
           break;
       case ExprType::F32:
           cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_));
           break;
       case ExprType::F64:
           cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_));
           break;
+      case ExprType::AnyRef:
+          cachedReturnJSValue_ = ObjectOrNullValue(*(JSObject**)&resultRef_);
+          break;
       default:
           MOZ_CRASH("result type");
     }
 }
 
 HandleValue
 DebugFrame::returnValue() const
 {
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1956,20 +1956,21 @@ static_assert(sizeof(Frame) % 16 == 0, "
 
 class DebugFrame
 {
     // The results field left uninitialized and only used during the baseline
     // compiler's return sequence to allow the debugger to inspect and modify
     // the return value of a frame being debugged.
     union
     {
-        int32_t resultI32_;
-        int64_t resultI64_;
-        float resultF32_;
-        double resultF64_;
+        int32_t  resultI32_;
+        int64_t  resultI64_;
+        intptr_t resultRef_;
+        float    resultF32_;
+        double   resultF64_;
     };
 
     // The returnValue() method returns a HandleValue pointing to this field.
     js::Value cachedReturnJSValue_;
 
     // The function index of this frame. Technically, this could be derived
     // given a PC into this frame (which could lookup the CodeRange which has
     // the function index), but this isn't always readily available.
--- a/js/xpconnect/idl/nsIXPCScriptable.idl
+++ b/js/xpconnect/idl/nsIXPCScriptable.idl
@@ -44,20 +44,20 @@ interface nsIXPConnectWrappedNative;
     #define XPC_SCRIPTABLE_WANT_FINALIZE                    (1 <<  6)
     #define XPC_SCRIPTABLE_WANT_CALL                        (1 <<  7)
     #define XPC_SCRIPTABLE_WANT_CONSTRUCT                   (1 <<  8)
     #define XPC_SCRIPTABLE_WANT_HASINSTANCE                 (1 <<  9)
     #define XPC_SCRIPTABLE_USE_JSSTUB_FOR_ADDPROPERTY       (1 << 10)
     #define XPC_SCRIPTABLE_USE_JSSTUB_FOR_DELPROPERTY       (1 << 11)
     // (1 << 12) is unused
     #define XPC_SCRIPTABLE_DONT_ENUM_QUERY_INTERFACE        (1 << 13)
-    #define XPC_SCRIPTABLE_DONT_ASK_INSTANCE_FOR_SCRIPTABLE (1 << 14)
-    #define XPC_SCRIPTABLE_CLASSINFO_INTERFACES_ONLY        (1 << 15)
+    // (1 << 14) is unused
+    // (1 << 15) is unused
     #define XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE   (1 << 16)
-    #define XPC_SCRIPTABLE_ALLOW_PROP_MODS_TO_PROTOTYPE     (1 << 17)
+    // (1 << 17) is unused
     #define XPC_SCRIPTABLE_IS_GLOBAL_OBJECT                 (1 << 18)
     #define XPC_SCRIPTABLE_DONT_REFLECT_INTERFACE_NAMES     (1 << 19)
 %}
 
 /**
  * Note: This is not really an XPCOM interface.  For example, callers must
  * guarantee that they set the *_retval of the various methods that return a
  * boolean to PR_TRUE before making the call.  Implementations may skip writing
@@ -95,18 +95,16 @@ interface nsIXPCScriptable : nsISupports
     boolean construct(in nsIXPConnectWrappedNative wrapper,
                      in JSContextPtr cx, in JSObjectPtr obj,
                      in JSCallArgsRef args);
 
     boolean hasInstance(in nsIXPConnectWrappedNative wrapper,
                        in JSContextPtr cx, in JSObjectPtr obj,
                        in jsval val, out boolean bp);
 
-    void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto);
-
 %{ C++
     #define GET_IT(f_, c_) \
     bool f_() { \
         return 0 != (GetScriptableFlags() & XPC_SCRIPTABLE_##c_); \
     }
 
     GET_IT(WantPreCreate,                WANT_PRECREATE)
     GET_IT(WantEnumerate,                WANT_ENUMERATE)
@@ -114,51 +112,15 @@ interface nsIXPCScriptable : nsISupports
     GET_IT(WantResolve,                  WANT_RESOLVE)
     GET_IT(WantFinalize,                 WANT_FINALIZE)
     GET_IT(WantCall,                     WANT_CALL)
     GET_IT(WantConstruct,                WANT_CONSTRUCT)
     GET_IT(WantHasInstance,              WANT_HASINSTANCE)
     GET_IT(UseJSStubForAddProperty,      USE_JSSTUB_FOR_ADDPROPERTY)
     GET_IT(UseJSStubForDelProperty,      USE_JSSTUB_FOR_DELPROPERTY)
     GET_IT(DontEnumQueryInterface,       DONT_ENUM_QUERY_INTERFACE)
-    GET_IT(DontAskInstanceForScriptable, DONT_ASK_INSTANCE_FOR_SCRIPTABLE)
-    GET_IT(ClassInfoInterfacesOnly,      CLASSINFO_INTERFACES_ONLY)
     GET_IT(AllowPropModsDuringResolve,   ALLOW_PROP_MODS_DURING_RESOLVE)
-    GET_IT(AllowPropModsToPrototype,     ALLOW_PROP_MODS_TO_PROTOTYPE)
     GET_IT(IsGlobalObject,               IS_GLOBAL_OBJECT)
     GET_IT(DontReflectInterfaceNames,    DONT_REFLECT_INTERFACE_NAMES)
 
     #undef GET_IT
 %}
 };
-
-%{ C++
-
-#include "nsAutoPtr.h"
-
-#define NS_XPCCLASSINFO_IID \
-{ 0x43b67f01, 0xd4ce, 0x4b82, \
- { 0xb3, 0xf8, 0xeb, 0xf2, 0x13, 0x60, 0xfb, 0x7e } }
-
-class NS_NO_VTABLE nsXPCClassInfo : public nsIClassInfo,
-                                    public nsIXPCScriptable
-{
-public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_XPCCLASSINFO_IID)
-
-  NS_IMETHOD_(MozExternalRefCountType) AddRef() override = 0;
-  NS_IMETHOD_(MozExternalRefCountType) Release() override = 0;
-
-  virtual void PreserveWrapper(nsISupports *aNative) = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsXPCClassInfo, NS_XPCCLASSINFO_IID)
-
-inline
-nsresult
-CallQueryInterface(nsISupports* aSourcePtr,
-                   RefPtrGetterAddRefs<nsXPCClassInfo> aDestPtr)
-{
-  return CallQueryInterface(aSourcePtr,
-                            static_cast<nsXPCClassInfo**>(aDestPtr));
-}
-
-%}
--- a/js/xpconnect/public/xpc_map_end.h
+++ b/js/xpconnect/public/xpc_map_end.h
@@ -94,16 +94,13 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Constru
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
 #if !((XPC_MAP_FLAGS) & XPC_SCRIPTABLE_WANT_HASINSTANCE)
 NS_IMETHODIMP XPC_MAP_CLASSNAME::HasInstance(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, JS::HandleValue val, bool* bp, bool* _retval)
     {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;}
 #endif
 
-NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreatePrototype(JSContext* cx, JSObject* proto)
-    {return NS_OK;}
-
 /**************************************************************/
 
 #undef XPC_MAP_CLASSNAME
 #undef XPC_MAP_QUOTED_CLASSNAME
 #undef XPC_MAP_FLAGS
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2915,17 +2915,17 @@ XPCJSRuntime::InitializeStrings(JSContex
     return true;
 }
 
 bool
 XPCJSRuntime::DescribeCustomObjects(JSObject* obj, const js::Class* clasp,
                                     char (&name)[72]) const
 {
 
-    if (!IS_PROTO_CLASS(clasp)) {
+    if (clasp != &XPC_WN_Proto_JSClass) {
         return false;
     }
 
     XPCWrappedNativeProto* p =
         static_cast<XPCWrappedNativeProto*>(xpc_GetJSPrivate(obj));
     nsCOMPtr<nsIXPCScriptable> scr = p->GetScriptable();
     if (!scr) {
         return false;
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -151,17 +151,17 @@ FinishCreate(XPCWrappedNativeScope* Scop
 nsresult
 XPCWrappedNative::WrapNewGlobal(xpcObjectHelper& nativeHelper,
                                 nsIPrincipal* principal,
                                 bool initStandardClasses,
                                 JS::CompartmentOptions& aOptions,
                                 XPCWrappedNative** wrappedGlobal)
 {
     AutoJSContext cx;
-    nsISupports* identity = nativeHelper.GetCanonical();
+    nsCOMPtr<nsISupports> identity = do_QueryInterface(nativeHelper.Object());
 
     // The object should specify that it's meant to be global.
     MOZ_ASSERT(nativeHelper.GetScriptableFlags() & XPC_SCRIPTABLE_IS_GLOBAL_OBJECT);
 
     // We shouldn't be reusing globals.
     MOZ_ASSERT(!nativeHelper.GetWrapperCache() ||
                !nativeHelper.GetWrapperCache()->GetWrapperPreserveColor());
 
@@ -193,32 +193,30 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
     // If requested, initialize the standard classes on the global.
     if (initStandardClasses && ! JS_InitStandardClasses(cx, global))
         return NS_ERROR_FAILURE;
 
     // Make a proto.
     XPCWrappedNativeProto* proto =
         XPCWrappedNativeProto::GetNewOrUsed(scope,
                                             nativeHelper.GetClassInfo(),
-                                            scrProto,
-                                            /* callPostCreatePrototype = */ false);
+                                            scrProto);
     if (!proto)
         return NS_ERROR_FAILURE;
 
     // Set up the prototype on the global.
     MOZ_ASSERT(proto->GetJSProtoObject());
     RootedObject protoObj(cx, proto->GetJSProtoObject());
     bool success = JS_SplicePrototype(cx, global, protoObj);
     if (!success)
         return NS_ERROR_FAILURE;
 
     // Construct the wrapper, which takes over the strong reference to the
     // native object.
-    RefPtr<XPCWrappedNative> wrapper =
-        new XPCWrappedNative(nativeHelper.forgetCanonical(), proto);
+    RefPtr<XPCWrappedNative> wrapper = new XPCWrappedNative(identity.forget(), proto);
 
     //
     // We don't call ::Init() on this wrapper, because our setup requirements
     // are different for globals. We do our setup inline here, instead.
     //
 
     wrapper->mScriptable = scrWrapper;
 
@@ -279,17 +277,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
                "We assume the caller already checked if it could get the "
                "wrapper from the cache.");
 
     nsresult rv;
 
     MOZ_ASSERT(!Scope->GetRuntime()->GCIsRunning(),
                "XPCWrappedNative::GetNewOrUsed called during GC");
 
-    nsISupports* identity = helper.GetCanonical();
+    nsCOMPtr<nsISupports> identity = do_QueryInterface(helper.Object());
 
     if (!identity) {
         NS_ERROR("This XPCOM object fails in QueryInterface to nsISupports!");
         return NS_ERROR_FAILURE;
     }
 
     RefPtr<XPCWrappedNative> wrapper;
 
@@ -401,31 +399,30 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     // Note that the security check happens inside FindTearOff - after the
     // wrapper is actually created, but before JS code can see it.
 
     if (info && !isClassInfoSingleton) {
         proto = XPCWrappedNativeProto::GetNewOrUsed(Scope, info, scrProto);
         if (!proto)
             return NS_ERROR_FAILURE;
 
-        wrapper = new XPCWrappedNative(helper.forgetCanonical(), proto);
+        wrapper = new XPCWrappedNative(identity.forget(), proto);
     } else {
         RefPtr<XPCNativeInterface> iface = Interface;
         if (!iface)
             iface = XPCNativeInterface::GetISupports();
 
         XPCNativeSetKey key(iface);
         RefPtr<XPCNativeSet> set =
             XPCNativeSet::GetNewOrUsed(&key);
 
         if (!set)
             return NS_ERROR_FAILURE;
 
-        wrapper = new XPCWrappedNative(helper.forgetCanonical(), Scope,
-                                       set.forget());
+        wrapper = new XPCWrappedNative(identity.forget(), Scope, set.forget());
     }
 
     MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(parent),
                "Xray wrapper being used to parent XPCWrappedNative?");
 
     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
     // after we have Init'd the wrapper but *before* we add it to the hashtable.
     // This would cause the mSet to get collected and we'd later crash. I've
@@ -545,24 +542,16 @@ XPCWrappedNative::Destroy()
 
 // This is factored out so that it can be called publicly.
 // static
 nsIXPCScriptable*
 XPCWrappedNative::GatherProtoScriptable(nsIClassInfo* classInfo)
 {
     MOZ_ASSERT(classInfo, "bad param");
 
-    nsXPCClassInfo* classInfoHelper = nullptr;
-    CallQueryInterface(classInfo, &classInfoHelper);
-    if (classInfoHelper) {
-        nsCOMPtr<nsIXPCScriptable> helper =
-          dont_AddRef(static_cast<nsIXPCScriptable*>(classInfoHelper));
-        return helper;
-    }
-
     nsCOMPtr<nsIXPCScriptable> helper;
     nsresult rv = classInfo->GetScriptableHelper(getter_AddRefs(helper));
     if (NS_SUCCEEDED(rv) && helper) {
         return helper;
     }
 
     return nullptr;
 }
@@ -578,23 +567,16 @@ XPCWrappedNative::GatherScriptable(nsISu
     MOZ_ASSERT(!*aScrWrapper, "bad param");
 
     nsCOMPtr<nsIXPCScriptable> scrProto;
     nsCOMPtr<nsIXPCScriptable> scrWrapper;
 
     // Get the class scriptable helper (if present)
     if (aClassInfo) {
         scrProto = GatherProtoScriptable(aClassInfo);
-
-        if (scrProto && scrProto->DontAskInstanceForScriptable()) {
-            scrWrapper = scrProto;
-            scrProto.forget(aScrProto);
-            scrWrapper.forget(aScrWrapper);
-            return;
-        }
     }
 
     // Do the same for the wrapper specific scriptable
     scrWrapper = do_QueryInterface(aObj);
     if (scrWrapper) {
         // A whole series of assertions to catch bad uses of scriptable flags on
         // the scrWrapper...
 
@@ -603,35 +585,20 @@ XPCWrappedNative::GatherScriptable(nsISu
         MOZ_ASSERT_IF(scrWrapper->WantPreCreate(),
                       scrProto && scrProto->WantPreCreate());
 
         // Can't set DONT_ENUM_QUERY_INTERFACE on an instance scriptable
         // without also setting it on the class scriptable (if present).
         MOZ_ASSERT_IF(scrWrapper->DontEnumQueryInterface() && scrProto,
                       scrProto->DontEnumQueryInterface());
 
-        // Can't set DONT_ASK_INSTANCE_FOR_SCRIPTABLE on an instance scriptable
-        // without also setting it on the class scriptable.
-        MOZ_ASSERT_IF(scrWrapper->DontAskInstanceForScriptable(),
-                      scrProto && scrProto->DontAskInstanceForScriptable());
-
-        // Can't set CLASSINFO_INTERFACES_ONLY on an instance scriptable
-        // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->ClassInfoInterfacesOnly() && scrProto,
-                      scrProto->ClassInfoInterfacesOnly());
-
         // Can't set ALLOW_PROP_MODS_DURING_RESOLVE on an instance scriptable
         // without also setting it on the class scriptable (if present).
         MOZ_ASSERT_IF(scrWrapper->AllowPropModsDuringResolve() && scrProto,
                       scrProto->AllowPropModsDuringResolve());
-
-        // Can't set ALLOW_PROP_MODS_TO_PROTOTYPE on an instance scriptable
-        // without also setting it on the class scriptable (if present).
-        MOZ_ASSERT_IF(scrWrapper->AllowPropModsToPrototype() && scrProto,
-                      scrProto->AllowPropModsToPrototype());
     } else {
         scrWrapper = scrProto;
     }
 
     scrProto.forget(aScrProto);
     scrWrapper.forget(aScrWrapper);
 }
 
@@ -988,25 +955,16 @@ XPCWrappedNative::InitTearOff(XPCWrapped
 
     const nsIID* iid = aInterface->GetIID();
     nsISupports* identity = GetIdentityObject();
 
     // This is an nsRefPtr instead of an nsCOMPtr because it may not be the
     // canonical nsISupports for this object.
     RefPtr<nsISupports> qiResult;
 
-    // If the scriptable helper forbids us from reflecting additional
-    // interfaces, then don't even try the QI, just fail.
-    if (mScriptable &&
-        mScriptable->ClassInfoInterfacesOnly() &&
-        !mSet->HasInterface(aInterface) &&
-        !mSet->HasInterfaceWithAncestor(aInterface)) {
-        return NS_ERROR_NO_INTERFACE;
-    }
-
     // We are about to call out to other code.
     // So protect our intended tearoff.
 
     aTearOff->SetReserved();
 
     if (NS_FAILED(identity->QueryInterface(*iid, getter_AddRefs(qiResult))) || !qiResult) {
         aTearOff->SetInterface(nullptr);
         return NS_ERROR_NO_INTERFACE;
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -247,28 +247,16 @@ DefinePropertyIfFound(XPCCallContext& cc
         else
             found = set->FindMember(id, &member, &iface);
     } else
         found = (nullptr != (member = iface->FindMember(id)));
 
     if (!found) {
         if (reflectToStringAndToSource) {
             JSNative call;
-            uint32_t flags = 0;
-
-            if (scr) {
-                nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(scr);
-
-                if (classInfo) {
-                    nsresult rv = classInfo->GetFlags(&flags);
-                    if (NS_FAILED(rv))
-                        return Throw(rv, ccx);
-                }
-            }
-
             if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_STRING)) {
                 call = XPC_WN_Shared_ToString;
                 name = xpccx->GetStringName(XPCJSContext::IDX_TO_STRING);
             } else if (id == xpccx->GetStringID(XPCJSContext::IDX_TO_SOURCE)) {
                 call = XPC_WN_Shared_ToSource;
                 name = xpccx->GetStringName(XPCJSContext::IDX_TO_SOURCE);
             } else if (id == SYMBOL_TO_JSID(
                                JS::GetWellKnownSymbol(ccx, JS::SymbolCode::toPrimitive)))
@@ -947,20 +935,19 @@ XPC_WN_GetterSetter(JSContext* cx, unsig
 
     ccx.SetCallInfo(iface, member, false);
     return XPCWrappedNative::GetAttribute(ccx);
 }
 
 /***************************************************************************/
 
 static bool
-XPC_WN_Shared_Proto_Enumerate(JSContext* cx, HandleObject obj)
+XPC_WN_Proto_Enumerate(JSContext* cx, HandleObject obj)
 {
-    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass ||
-               js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
+    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_Proto_JSClass,
                "bad proto");
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (!self)
         return false;
 
     XPCNativeSet* set = self->GetSet();
     if (!set)
@@ -981,106 +968,53 @@ XPC_WN_Shared_Proto_Enumerate(JSContext*
                 return false;
         }
     }
 
     return true;
 }
 
 static void
-XPC_WN_Shared_Proto_Finalize(js::FreeOp* fop, JSObject* obj)
+XPC_WN_Proto_Finalize(js::FreeOp* fop, JSObject* obj)
 {
     // This can be null if xpc shutdown has already happened
     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (p)
         p->JSProtoObjectFinalized(fop, obj);
 }
 
 static size_t
-XPC_WN_Shared_Proto_ObjectMoved(JSObject* obj, JSObject* old)
+XPC_WN_Proto_ObjectMoved(JSObject* obj, JSObject* old)
 {
     // This can be null if xpc shutdown has already happened
     XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (!p)
         return 0;
 
     p->JSProtoObjectMoved(obj, old);
     return 0;
 }
 
 static void
-XPC_WN_Shared_Proto_Trace(JSTracer* trc, JSObject* obj)
+XPC_WN_Proto_Trace(JSTracer* trc, JSObject* obj)
 {
     // This can be null if xpc shutdown has already happened
     XPCWrappedNativeProto* p =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (p)
         p->TraceInside(trc);
 }
 
 /*****************************************************/
 
 static bool
-XPC_WN_ModsAllowed_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvep)
-{
-    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_Proto_JSClass,
-               "bad proto");
-
-    XPCWrappedNativeProto* self =
-        (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
-    if (!self)
-        return false;
-
-    XPCCallContext ccx(cx);
-    if (!ccx.IsValid())
-        return false;
-
-    nsCOMPtr<nsIXPCScriptable> scr = self->GetScriptable();
-    return DefinePropertyIfFound(ccx, obj, id,
-                                 self->GetSet(), nullptr, nullptr,
-                                 self->GetScope(),
-                                 true, nullptr, nullptr, scr,
-                                 JSPROP_ENUMERATE, resolvep);
-}
-
-static const js::ClassOps XPC_WN_ModsAllowed_Proto_JSClassOps = {
-    nullptr,                            // addProperty
-    nullptr,                            // delProperty
-    XPC_WN_Shared_Proto_Enumerate,      // enumerate
-    nullptr,                            // newEnumerate
-    XPC_WN_ModsAllowed_Proto_Resolve,   // resolve
-    nullptr,                            // mayResolve
-    XPC_WN_Shared_Proto_Finalize,       // finalize
-    nullptr,                            // call
-    nullptr,                            // construct
-    nullptr,                            // hasInstance
-    XPC_WN_Shared_Proto_Trace,          // trace
-};
-
-static const js::ClassExtension XPC_WN_Shared_Proto_ClassExtension = {
-    nullptr,    /* weakmapKeyDelegateOp */
-    XPC_WN_Shared_Proto_ObjectMoved
-};
-
-const js::Class XPC_WN_ModsAllowed_Proto_JSClass = {
-    "XPC_WN_ModsAllowed_Proto_JSClass",
-    XPC_WRAPPER_FLAGS,
-    &XPC_WN_ModsAllowed_Proto_JSClassOps,
-    JS_NULL_CLASS_SPEC,
-    &XPC_WN_Shared_Proto_ClassExtension,
-    JS_NULL_OBJECT_OPS
-};
-
-/***************************************************************************/
-
-static bool
 XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext* cx, HandleObject obj, HandleId id,
                                         HandleValue v)
 {
-    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
+    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_Proto_JSClass,
                "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (!self)
         return false;
 
     XPCCallContext ccx(cx);
@@ -1090,19 +1024,19 @@ XPC_WN_OnlyIWrite_Proto_AddPropertyStub(
     // Allow XPConnect to add the property only
     if (ccx.GetResolveName() == id)
         return true;
 
     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);
 }
 
 static bool
-XPC_WN_NoMods_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
+XPC_WN_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
 {
-    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_Proto_JSClass,
+    MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_Proto_JSClass,
                "bad proto");
 
     XPCWrappedNativeProto* self =
         (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj);
     if (!self)
         return false;
 
     XPCCallContext ccx(cx);
@@ -1115,36 +1049,41 @@ XPC_WN_NoMods_Proto_Resolve(JSContext* c
                                  self->GetSet(), nullptr, nullptr,
                                  self->GetScope(),
                                  true, nullptr, nullptr, scr,
                                  JSPROP_READONLY |
                                  JSPROP_PERMANENT |
                                  JSPROP_ENUMERATE, resolvedp);
 }
 
-static const js::ClassOps XPC_WN_NoMods_Proto_JSClassOps = {
+static const js::ClassOps XPC_WN_Proto_JSClassOps = {
     XPC_WN_OnlyIWrite_Proto_AddPropertyStub,   // addProperty
     XPC_WN_CannotDeletePropertyStub,           // delProperty
-    XPC_WN_Shared_Proto_Enumerate,             // enumerate
+    XPC_WN_Proto_Enumerate,                    // enumerate
     nullptr,                                   // newEnumerate
-    XPC_WN_NoMods_Proto_Resolve,               // resolve
+    XPC_WN_Proto_Resolve,                      // resolve
     nullptr,                                   // mayResolve
-    XPC_WN_Shared_Proto_Finalize,              // finalize
+    XPC_WN_Proto_Finalize,                     // finalize
     nullptr,                                   // call
     nullptr,                                   // construct
     nullptr,                                   // hasInstance
-    XPC_WN_Shared_Proto_Trace,                 // trace
+    XPC_WN_Proto_Trace,                        // trace
 };
 
-const js::Class XPC_WN_NoMods_Proto_JSClass = {
-    "XPC_WN_NoMods_Proto_JSClass",
+static const js::ClassExtension XPC_WN_Proto_ClassExtension = {
+    nullptr,    /* weakmapKeyDelegateOp */
+    XPC_WN_Proto_ObjectMoved
+};
+
+const js::Class XPC_WN_Proto_JSClass = {
+    "XPC_WN_Proto_JSClass",
     XPC_WRAPPER_FLAGS,
-    &XPC_WN_NoMods_Proto_JSClassOps,
+    &XPC_WN_Proto_JSClassOps,
     JS_NULL_CLASS_SPEC,
-    &XPC_WN_Shared_Proto_ClassExtension,
+    &XPC_WN_Proto_ClassExtension,
     JS_NULL_OBJECT_OPS
 };
 
 /***************************************************************************/
 
 static bool
 XPC_WN_TearOff_Enumerate(JSContext* cx, HandleObject obj)
 {
--- a/js/xpconnect/src/XPCWrappedNativeProto.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp
@@ -45,64 +45,34 @@ XPCWrappedNativeProto::~XPCWrappedNative
 #endif
 
     // Note that our weak ref to mScope is not to be trusted at this point.
 
     XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo);
 }
 
 bool
-XPCWrappedNativeProto::Init(nsIXPCScriptable* scriptable,
-                            bool callPostCreatePrototype)
+XPCWrappedNativeProto::Init(nsIXPCScriptable* scriptable)
 {
     AutoJSContext cx;
     mScriptable = scriptable;
 
-    const js::Class* jsclazz =
-        (mScriptable && mScriptable->AllowPropModsToPrototype())
-        ? &XPC_WN_ModsAllowed_Proto_JSClass
-        : &XPC_WN_NoMods_Proto_JSClass;
-
     JS::RootedObject global(cx, mScope->GetGlobalJSObject());
     JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, global));
-    mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(jsclazz),
+    mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(&XPC_WN_Proto_JSClass),
                                                 proto);
 
     bool success = !!mJSProtoObject;
     if (success) {
         JS_SetPrivate(mJSProtoObject, this);
-        if (callPostCreatePrototype)
-            success = CallPostCreatePrototype();
     }
 
     return success;
 }
 
-bool
-XPCWrappedNativeProto::CallPostCreatePrototype()
-{
-    AutoJSContext cx;
-
-    // Nothing to do if we don't have a scriptable callback.
-    if (!mScriptable)
-        return true;
-
-    // Call the helper. This can handle being called if it's not implemented,
-    // so we don't have to check any sort of "want" here. See xpc_map_end.h.
-    nsresult rv = mScriptable->PostCreatePrototype(cx, mJSProtoObject);
-    if (NS_FAILED(rv)) {
-        JS_SetPrivate(mJSProtoObject, nullptr);
-        mJSProtoObject = nullptr;
-        XPCThrower::Throw(rv, cx);
-        return false;
-    }
-
-    return true;
-}
-
 void
 XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
 {
     MOZ_ASSERT(obj == mJSProtoObject, "huh?");
 
 #ifdef DEBUG
     // Check that this object has already been swept from the map.
     ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
@@ -133,18 +103,17 @@ XPCWrappedNativeProto::SystemIsBeingShut
         mJSProtoObject = nullptr;
     }
 }
 
 // static
 XPCWrappedNativeProto*
 XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
                                     nsIClassInfo* classInfo,
-                                    nsIXPCScriptable* scriptable,
-                                    bool callPostCreatePrototype)
+                                    nsIXPCScriptable* scriptable)
 {
     AutoJSContext cx;
     MOZ_ASSERT(scope, "bad param");
     MOZ_ASSERT(classInfo, "bad param");
 
     AutoMarkingWrappedNativeProtoPtr proto(cx);
     ClassInfo2WrappedNativeProtoMap* map = nullptr;
 
@@ -154,17 +123,17 @@ XPCWrappedNativeProto::GetNewOrUsed(XPCW
         return proto;
 
     RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(classInfo);
     if (!set)
         return nullptr;
 
     proto = new XPCWrappedNativeProto(scope, classInfo, set.forget());
 
-    if (!proto || !proto->Init(scriptable, callPostCreatePrototype)) {
+    if (!proto || !proto->Init(scriptable)) {
         delete proto.get();
         return nullptr;
     }
 
     map->Add(classInfo, proto);
 
     return proto;
 }
--- a/js/xpconnect/src/moz.build
+++ b/js/xpconnect/src/moz.build
@@ -1,17 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS += [
     'BackstagePass.h',
-    'qsObjectHelper.h',
     'XPCJSMemoryReporter.h',
     'xpcObjectHelper.h',
     'xpcpublic.h',
 ]
 
 UNIFIED_SOURCES += [
     'ExportHelpers.cpp',
     'nsXPConnect.cpp',
deleted file mode 100644
--- a/js/xpconnect/src/qsObjectHelper.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set ts=8 sts=4 et sw=4 tw=99: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef qsObjectHelper_h
-#define qsObjectHelper_h
-
-#include "xpcObjectHelper.h"
-
-#include "nsCOMPtr.h"
-#include "nsWrapperCache.h"
-#include "mozilla/TypeTraits.h"
-
-class qsObjectHelper : public xpcObjectHelper
-{
-public:
-    template <class T>
-    inline
-    qsObjectHelper(T* aObject, nsWrapperCache* aCache)
-        : xpcObjectHelper(ToSupports(aObject), ToCanonicalSupports(aObject),
-                          aCache)
-    {}
-
-    template <class T>
-    inline
-    qsObjectHelper(nsCOMPtr<T>& aObject, nsWrapperCache* aCache)
-        : xpcObjectHelper(ToSupports(aObject.get()),
-                          ToCanonicalSupports(aObject.get()), aCache)
-    {
-        if (mCanonical) {
-            // Transfer the strong reference.
-            mCanonicalStrong = dont_AddRef(mCanonical);
-            aObject.forget();
-        }
-    }
-
-    template <class T>
-    inline
-    qsObjectHelper(RefPtr<T>& aObject, nsWrapperCache* aCache)
-        : xpcObjectHelper(ToSupports(aObject.get()),
-                          ToCanonicalSupports(aObject.get()), aCache)
-    {
-        if (mCanonical) {
-            // Transfer the strong reference.
-            mCanonicalStrong = dont_AddRef(mCanonical);
-            aObject.forget();
-        }
-    }
-};
-
-#endif
--- a/js/xpconnect/src/xpcObjectHelper.h
+++ b/js/xpconnect/src/xpcObjectHelper.h
@@ -21,117 +21,56 @@
 #include "nsISupports.h"
 #include "nsIXPCScriptable.h"
 #include "nsWrapperCache.h"
 
 class xpcObjectHelper
 {
 public:
     explicit xpcObjectHelper(nsISupports* aObject, nsWrapperCache* aCache = nullptr)
-      : mCanonical(nullptr)
-      , mObject(aObject)
+      : mObject(aObject)
       , mCache(aCache)
     {
-        if (!mCache) {
-            if (aObject)
-                CallQueryInterface(aObject, &mCache);
-            else
-                mCache = nullptr;
+        if (!mCache && aObject) {
+            CallQueryInterface(aObject, &mCache);
         }
     }
 
     nsISupports* Object()
     {
         return mObject;
     }
 
-    nsISupports* GetCanonical()
-    {
-        if (!mCanonical) {
-            mCanonicalStrong = do_QueryInterface(mObject);
-            mCanonical = mCanonicalStrong;
-        }
-        return mCanonical;
-    }
-
-    already_AddRefed<nsISupports> forgetCanonical()
-    {
-        MOZ_ASSERT(mCanonical, "Huh, no canonical to forget?");
-
-        if (!mCanonicalStrong)
-            mCanonicalStrong = mCanonical;
-        mCanonical = nullptr;
-        return mCanonicalStrong.forget();
-    }
-
     nsIClassInfo* GetClassInfo()
     {
-        if (mXPCClassInfo)
-          return mXPCClassInfo;
         if (!mClassInfo)
             mClassInfo = do_QueryInterface(mObject);
         return mClassInfo;
     }
-    nsXPCClassInfo* GetXPCClassInfo()
-    {
-        if (!mXPCClassInfo) {
-            CallQueryInterface(mObject, getter_AddRefs(mXPCClassInfo));
-        }
-        return mXPCClassInfo;
-    }
-
-    already_AddRefed<nsXPCClassInfo> forgetXPCClassInfo()
-    {
-        GetXPCClassInfo();
-
-        return mXPCClassInfo.forget();
-    }
 
     // We assert that we can reach an nsIXPCScriptable somehow.
     uint32_t GetScriptableFlags()
     {
-        // Try getting an nsXPCClassInfo - this handles DOM scriptable helpers.
-        nsCOMPtr<nsIXPCScriptable> sinfo = GetXPCClassInfo();
-
-        // If that didn't work, try just QI-ing. This handles BackstagePass.
-        if (!sinfo)
-            sinfo = do_QueryInterface(GetCanonical());
+        nsCOMPtr<nsIXPCScriptable> sinfo = do_QueryInterface(mObject);
 
         // We should have something by now.
         MOZ_ASSERT(sinfo);
 
         // Grab the flags.
         return sinfo->GetScriptableFlags();
     }
 
     nsWrapperCache* GetWrapperCache()
     {
         return mCache;
     }
 
-protected:
-    xpcObjectHelper(nsISupports* aObject, nsISupports* aCanonical,
-                    nsWrapperCache* aCache)
-      : mCanonical(aCanonical)
-      , mObject(aObject)
-      , mCache(aCache)
-    {
-        if (!mCache && aObject)
-            CallQueryInterface(aObject, &mCache);
-    }
-
-    nsCOMPtr<nsISupports>    mCanonicalStrong;
-    nsISupports* MOZ_UNSAFE_REF("xpcObjectHelper has been specifically optimized "
-                                "to avoid unnecessary AddRefs and Releases. "
-                                "(see bug 565742)") mCanonical;
-
 private:
     xpcObjectHelper(xpcObjectHelper& aOther) = delete;
 
     nsISupports* MOZ_UNSAFE_REF("xpcObjectHelper has been specifically optimized "
                                 "to avoid unnecessary AddRefs and Releases. "
                                 "(see bug 565742)") mObject;
     nsWrapperCache*          mCache;
     nsCOMPtr<nsIClassInfo>   mClassInfo;
-    RefPtr<nsXPCClassInfo> mXPCClassInfo;
 };
 
 #endif
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -779,38 +779,28 @@ private:
 *
 ****************************************************************************
 ***************************************************************************/
 
 // These are the various JSClasses and callbacks whose use that required
 // visibility from more than one .cpp file.
 
 extern const js::Class XPC_WN_NoHelper_JSClass;
-extern const js::Class XPC_WN_NoMods_Proto_JSClass;
-extern const js::Class XPC_WN_ModsAllowed_Proto_JSClass;
+extern const js::Class XPC_WN_Proto_JSClass;
 extern const js::Class XPC_WN_Tearoff_JSClass;
 #define XPC_WN_TEAROFF_RESERVED_SLOTS 1
 #define XPC_WN_TEAROFF_FLAT_OBJECT_SLOT 0
 extern const js::Class XPC_WN_NoHelper_Proto_JSClass;
 
 extern bool
 XPC_WN_CallMethod(JSContext* cx, unsigned argc, JS::Value* vp);
 
 extern bool
 XPC_WN_GetterSetter(JSContext* cx, unsigned argc, JS::Value* vp);
 
-// Maybe this macro should check for class->enumerate ==
-// XPC_WN_Shared_Proto_Enumerate or something rather than checking for
-// 4 classes?
-static inline bool IS_PROTO_CLASS(const js::Class* clazz)
-{
-    return clazz == &XPC_WN_NoMods_Proto_JSClass ||
-           clazz == &XPC_WN_ModsAllowed_Proto_JSClass;
-}
-
 /***************************************************************************/
 // XPCWrappedNativeScope is one-to-one with a JS global object.
 
 class nsXPCComponentsBase;
 class XPCWrappedNativeScope final
 {
 public:
 
@@ -1272,18 +1262,17 @@ class XPCNativeSet final
 // for XPCWrappedNative whose native objects expose nsIClassInfo.
 
 class XPCWrappedNativeProto final
 {
 public:
     static XPCWrappedNativeProto*
     GetNewOrUsed(XPCWrappedNativeScope* scope,
                  nsIClassInfo* classInfo,
-                 nsIXPCScriptable* scriptable,
-                 bool callPostCreatePrototype = true);
+                 nsIXPCScriptable* scriptable);
 
     XPCWrappedNativeScope*
     GetScope()   const {return mScope;}
 
     XPCJSRuntime*
     GetRuntime() const {return mScope->GetRuntime();}
 
     JSObject*
@@ -1296,17 +1285,16 @@ public:
     GetClassInfo()     const {return mClassInfo;}
 
     XPCNativeSet*
     GetSet()           const {return mSet;}
 
     nsIXPCScriptable*
     GetScriptable() const { return mScriptable; }
 
-    bool CallPostCreatePrototype();
     void JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj);
     void JSProtoObjectMoved(JSObject* obj, const JSObject* old);
 
     void SystemIsBeingShutDown();
 
     void DebugDump(int16_t depth);
 
     void TraceSelf(JSTracer* trc) {
@@ -1340,17 +1328,17 @@ protected:
     XPCWrappedNativeProto(const XPCWrappedNativeProto& r) = delete;
     XPCWrappedNativeProto& operator= (const XPCWrappedNativeProto& r) = delete;
 
     // hide ctor
     XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
                           nsIClassInfo* ClassInfo,
                           already_AddRefed<XPCNativeSet>&& Set);
 
-    bool Init(nsIXPCScriptable* scriptable, bool callPostCreatePrototype);
+    bool Init(nsIXPCScriptable* scriptable);
 
 private:
 #ifdef DEBUG
     static int32_t gDEBUG_LiveProtoCount;
 #endif
 
 private:
     XPCWrappedNativeScope*   mScope;
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -1446,21 +1446,16 @@ static bool
 IsWindow(JSContext* cx, JSObject* wrapper)
 {
     return !!AsWindow(cx, wrapper);
 }
 
 void
 XPCWrappedNativeXrayTraits::preserveWrapper(JSObject* target)
 {
-    XPCWrappedNative* wn = XPCWrappedNative::Get(target);
-    RefPtr<nsXPCClassInfo> ci;
-    CallQueryInterface(wn->Native(), getter_AddRefs(ci));
-    if (ci)
-        ci->PreserveWrapper(wn->Native());
 }
 
 static bool
 XrayToString(JSContext* cx, unsigned argc, JS::Value* vp);
 
 bool
 XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext* cx, HandleObject wrapper,
                                                   HandleObject holder, HandleId id,
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -255,20 +255,12 @@ nsFrameManager::RestoreFrameState(nsIFra
     nsFrameList::Enumerator childFrames(lists.CurrentList());
     for (; !childFrames.AtEnd(); childFrames.Next()) {
       RestoreFrameState(childFrames.get(), aState);
     }
   }
 }
 
 void
-nsFrameManager::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
-{
-  if (nsCOMPtr<nsIContent> content = aContent) {
-    content->UnbindFromTree();
-  }
-}
-
-void
 nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
 {
   aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
 }
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -88,18 +88,16 @@ public:
 
   /*
    * Add/restore state for one frame
    */
   void CaptureFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
 
   void RestoreFrameStateFor(nsIFrame* aFrame, nsILayoutHistoryState* aState);
 
-  void DestroyAnonymousContent(already_AddRefed<nsIContent> aContent);
-
   void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
 
 protected:
   // weak link, because the pres shell owns us
   nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
   nsIFrame* mRootFrame;
 };
 
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -446,16 +446,17 @@ nsTextControlFrame::InitializeEagerlyIfN
 }
 
 nsresult
 nsTextControlFrame::CreateRootNode()
 {
   MOZ_ASSERT(!mRootNode);
 
   mRootNode = CreateEmptyDiv(*this);
+  mRootNode->SetIsNativeAnonymousRoot();
 
   mMutationObserver = new nsAnonDivObserver(*this);
   mRootNode->AddMutationObserver(mMutationObserver);
 
   // Make our root node editable
   mRootNode->SetFlags(NODE_IS_EDITABLE);
 
   // Set the necessary classes on the text control. We use class values instead
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -241,18 +241,20 @@ nsReflowStatus::UpdateTruncated(const Re
     mTruncated = false;
   }
 }
 
 /* static */ void
 nsIFrame::DestroyAnonymousContent(nsPresContext* aPresContext,
                                   already_AddRefed<nsIContent>&& aContent)
 {
-  aPresContext->PresShell()->FrameConstructor()
-              ->DestroyAnonymousContent(Move(aContent));
+  if (nsCOMPtr<nsIContent> content = aContent) {
+    aPresContext->EventStateManager()->NativeAnonymousContentRemoved(content);
+    content->UnbindFromTree();
+  }
 }
 
 // Formerly the nsIFrameDebug interface
 
 #ifdef DEBUG
 std::ostream& operator<<(std::ostream& aStream,
                          const nsReflowStatus& aStatus)
 {
--- a/layout/style/CSSValue.h
+++ b/layout/style/CSSValue.h
@@ -4,39 +4,48 @@
  * 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/. */
 
 /* DOM object representing values in DOM computed style */
 
 #ifndef mozilla_dom_CSSValue_h_
 #define mozilla_dom_CSSValue_h_
 
-#include "nsWrapperCache.h"
 #include "nsStringFwd.h"
+#include "mozilla/RefCounted.h"
 
 class nsROCSSPrimitiveValue;
 namespace mozilla {
 class ErrorResult;
 } // namespace mozilla
 
 namespace mozilla {
 namespace dom {
 
 /**
  * CSSValue - a DOM object representing values in DOM computed style.
  */
-class CSSValue : public nsISupports,
-                 public nsWrapperCache
+class CSSValue : public RefCounted<CSSValue>
 {
 public:
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(CSSValue);
+  enum : uint16_t {
+    CSS_INHERIT,
+    CSS_PRIMITIVE_VALUE,
+    CSS_VALUE_LIST,
+    CSS_CUSTOM,
+  };
+
   // CSSValue
   virtual void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) = 0;
   virtual void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) = 0;
   virtual uint16_t CssValueType() const = 0;
 
+  virtual ~CSSValue() { };
+
   // Downcasting
 
   /**
    * Return this as a nsROCSSPrimitiveValue* if its a primitive value, and null
    * otherwise.
    *
    * Defined in nsROCSSPrimitiveValue.h.
    */
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -8,17 +8,16 @@
 
 #include "nsComputedDOMStyle.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/FontPropertyTypes.h"
 #include "mozilla/Preferences.h"
 
 #include "nsError.h"
-#include "mozilla/dom/CSSPrimitiveValueBinding.h"
 #include "nsIFrame.h"
 #include "nsIFrameInlines.h"
 #include "mozilla/ComputedStyle.h"
 #include "nsIScrollableFrame.h"
 #include "nsContentUtils.h"
 #include "nsIContent.h"
 
 #include "nsDOMCSSRect.h"
@@ -1362,17 +1361,17 @@ nsComputedDOMStyle::DoGetContent()
       case eStyleContentType_Attr: {
         // XXXbholley: We don't correctly serialize namespaces here. Doing so
         // would require either storing the prefix on the nsStyleContentAttr,
         // or poking at the namespaces in the stylesheet to map from the
         // namespace URL.
         nsAutoString str;
         nsStyleUtil::AppendEscapedCSSIdent(
           nsDependentString(data.GetAttr()->mName->GetUTF16String()), str);
-        val->SetString(str, CSSPrimitiveValueBinding::CSS_ATTR);
+        val->SetString(str, nsROCSSPrimitiveValue::CSS_ATTR);
         break;
       }
       case eStyleContentType_Counter:
       case eStyleContentType_Counters: {
         /* FIXME: counters should really use an object */
         nsAutoString str;
         if (type == eStyleContentType_Counter) {
           str.AppendLiteral("counter(");
@@ -1387,17 +1386,17 @@ nsComputedDOMStyle::DoGetContent()
           nsStyleUtil::AppendEscapedCSSString(counters->mSeparator, str);
         }
         if (counters->mCounterStyle != CounterStyleManager::GetDecimalStyle()) {
           str.AppendLiteral(", ");
           AppendCounterStyle(counters->mCounterStyle, str);
         }
 
         str.Append(char16_t(')'));
-        val->SetString(str, CSSPrimitiveValueBinding::CSS_COUNTER);
+        val->SetString(str, nsROCSSPrimitiveValue::CSS_COUNTER);
         break;
       }
       case eStyleContentType_OpenQuote:
         val->SetIdent(eCSSKeyword_open_quote);
         break;
       case eStyleContentType_CloseQuote:
         val->SetIdent(eCSSKeyword_close_quote);
         break;
--- a/layout/style/nsDOMCSSRGBColor.cpp
+++ b/layout/style/nsDOMCSSRGBColor.cpp
@@ -3,38 +3,23 @@
 /* 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/. */
 
 /* DOM object representing color values in DOM computed style */
 
 #include "nsDOMCSSRGBColor.h"
 
-#include "mozilla/dom/RGBColorBinding.h"
 #include "nsROCSSPrimitiveValue.h"
 
 using namespace mozilla;
 
 nsDOMCSSRGBColor::nsDOMCSSRGBColor(nsROCSSPrimitiveValue* aRed,
                                    nsROCSSPrimitiveValue* aGreen,
                                    nsROCSSPrimitiveValue* aBlue,
                                    nsROCSSPrimitiveValue* aAlpha,
                                    bool aHasAlpha)
   : mRed(aRed), mGreen(aGreen), mBlue(aBlue), mAlpha(aAlpha)
   , mHasAlpha(aHasAlpha)
 {
 }
 
-nsDOMCSSRGBColor::~nsDOMCSSRGBColor(void)
-{
-}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSRGBColor, mAlpha,  mBlue, mGreen, mRed)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsDOMCSSRGBColor, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsDOMCSSRGBColor, Release)
-
-JSObject*
-nsDOMCSSRGBColor::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return dom::RGBColorBinding::Wrap(aCx, this, aGivenProto);
-}
-
+nsDOMCSSRGBColor::~nsDOMCSSRGBColor() = default;
--- a/layout/style/nsDOMCSSRGBColor.h
+++ b/layout/style/nsDOMCSSRGBColor.h
@@ -5,33 +5,30 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* DOM object representing color values in DOM computed style */
 
 #ifndef nsDOMCSSRGBColor_h__
 #define nsDOMCSSRGBColor_h__
 
 #include "mozilla/Attributes.h"
-#include "nsWrapperCache.h"
+#include "mozilla/RefPtr.h"
 
 class nsROCSSPrimitiveValue;
 
-class nsDOMCSSRGBColor : public nsWrapperCache
+class nsDOMCSSRGBColor final : public mozilla::RefCounted<nsDOMCSSRGBColor>
 {
 public:
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(nsDOMCSSRGBColor);
   nsDOMCSSRGBColor(nsROCSSPrimitiveValue* aRed,
                    nsROCSSPrimitiveValue* aGreen,
                    nsROCSSPrimitiveValue* aBlue,
                    nsROCSSPrimitiveValue* aAlpha,
                    bool aHasAlpha);
 
-  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsDOMCSSRGBColor)
-
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(nsDOMCSSRGBColor)
-
   bool HasAlpha() const { return mHasAlpha; }
 
   // RGBColor webidl interface
   nsROCSSPrimitiveValue* Red() const
   {
     return mRed;
   }
   nsROCSSPrimitiveValue* Green() const
@@ -42,26 +39,19 @@ public:
   {
     return mBlue;
   }
   nsROCSSPrimitiveValue* Alpha() const
   {
     return mAlpha;
   }
 
-  nsISupports* GetParentObject() const
-  {
-    return nullptr;
-  }
+  ~nsDOMCSSRGBColor();
 
-  JSObject *WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) final;
-
-private:
-  virtual ~nsDOMCSSRGBColor(void);
-
+protected:
   RefPtr<nsROCSSPrimitiveValue> mRed;
   RefPtr<nsROCSSPrimitiveValue> mGreen;
   RefPtr<nsROCSSPrimitiveValue> mBlue;
   RefPtr<nsROCSSPrimitiveValue> mAlpha;
   bool mHasAlpha;
 };
 
 #endif // nsDOMCSSRGBColor_h__
--- a/layout/style/nsDOMCSSRect.cpp
+++ b/layout/style/nsDOMCSSRect.cpp
@@ -3,40 +3,21 @@
 /* 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/. */
 
 /* DOM object representing rectangle values in DOM computed style */
 
 #include "nsDOMCSSRect.h"
 
-#include "mozilla/dom/RectBinding.h"
 #include "nsROCSSPrimitiveValue.h"
 
 using namespace mozilla;
 
 nsDOMCSSRect::nsDOMCSSRect(nsROCSSPrimitiveValue* aTop,
                            nsROCSSPrimitiveValue* aRight,
                            nsROCSSPrimitiveValue* aBottom,
                            nsROCSSPrimitiveValue* aLeft)
   : mTop(aTop), mRight(aRight), mBottom(aBottom), mLeft(aLeft)
 {
 }
 
-nsDOMCSSRect::~nsDOMCSSRect(void)
-{
-}
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSRect)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSRect)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSRect)
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSRect, mTop, mBottom, mLeft, mRight)
-
-JSObject*
-nsDOMCSSRect::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
-{
- return dom::RectBinding::Wrap(cx, this, aGivenProto);
-}
+nsDOMCSSRect::~nsDOMCSSRect() = default;
--- a/layout/style/nsDOMCSSRect.h
+++ b/layout/style/nsDOMCSSRect.h
@@ -5,44 +5,36 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* DOM object representing rectangle values in DOM computed style */
 
 #ifndef nsDOMCSSRect_h_
 #define nsDOMCSSRect_h_
 
 #include "mozilla/Attributes.h"
-#include "nsCycleCollectionParticipant.h"
-#include "nsWrapperCache.h"
+#include "mozilla/RefPtr.h"
 
 class nsROCSSPrimitiveValue;
 
-class nsDOMCSSRect final : public nsISupports,
-                           public nsWrapperCache
+class nsDOMCSSRect final : public RefCounted<nsDOMCSSRect>
 {
 public:
+  MOZ_DECLARE_REFCOUNTED_TYPENAME(nsDOMCSSRect);
+
   nsDOMCSSRect(nsROCSSPrimitiveValue* aTop,
                nsROCSSPrimitiveValue* aRight,
                nsROCSSPrimitiveValue* aBottom,
                nsROCSSPrimitiveValue* aLeft);
 
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCSSRect)
-
   nsROCSSPrimitiveValue* Top() const { return mTop; }
   nsROCSSPrimitiveValue* Right() const { return mRight; }
   nsROCSSPrimitiveValue* Bottom() const { return mBottom; }
   nsROCSSPrimitiveValue* Left() const { return mLeft; }
 
-  nsISupports* GetParentObject() const { return nullptr; }
-
-  JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) final;
-
-protected:
-  virtual ~nsDOMCSSRect(void);
+  ~nsDOMCSSRect();
 
 private:
   RefPtr<nsROCSSPrimitiveValue> mTop;
   RefPtr<nsROCSSPrimitiveValue> mRight;
   RefPtr<nsROCSSPrimitiveValue> mBottom;
   RefPtr<nsROCSSPrimitiveValue> mLeft;
 };
 
--- a/layout/style/nsDOMCSSValueList.cpp
+++ b/layout/style/nsDOMCSSValueList.cpp
@@ -2,48 +2,29 @@
 /* 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/. */
 
 /* DOM object representing lists of values in DOM computed style */
 
 #include "nsDOMCSSValueList.h"
-#include "mozilla/dom/CSSValueBinding.h"
-#include "mozilla/dom/CSSValueListBinding.h"
+#include "nsString.h"
+#include "mozilla/ErrorResult.h"
 #include "mozilla/Move.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsDOMCSSValueList::nsDOMCSSValueList(bool aCommaDelimited, bool aReadonly)
   : CSSValue(), mCommaDelimited(aCommaDelimited), mReadonly(aReadonly)
 {
 }
 
-nsDOMCSSValueList::~nsDOMCSSValueList()
-{
-}
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSValueList)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSValueList)
-
-// QueryInterface implementation for nsDOMCSSValueList
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSValueList)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, CSSValue)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSValueList, mCSSValues)
-
-JSObject*
-nsDOMCSSValueList::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
-  return dom::CSSValueListBinding::Wrap(cx, this, aGivenProto);
-}
+nsDOMCSSValueList::~nsDOMCSSValueList() = default;
 
 void
 nsDOMCSSValueList::AppendCSSValue(already_AddRefed<CSSValue> aValue)
 {
   RefPtr<CSSValue> val = aValue;
   mCSSValues.AppendElement(Move(val));
 }
 
@@ -104,10 +85,10 @@ nsDOMCSSValueList::SetCssText(const nsAS
   }
 
   MOZ_ASSERT_UNREACHABLE("Can't SetCssText yet: please write me!");
 }
 
 uint16_t
 nsDOMCSSValueList::CssValueType() const
 {
-  return CSSValueBinding::CSS_VALUE_LIST;
+  return CSSValue::CSS_VALUE_LIST;
 }
--- a/layout/style/nsDOMCSSValueList.h
+++ b/layout/style/nsDOMCSSValueList.h
@@ -10,19 +10,16 @@
 #define nsDOMCSSValueList_h___
 
 #include "CSSValue.h"
 #include "nsTArray.h"
 
 class nsDOMCSSValueList final : public mozilla::dom::CSSValue
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCSSValueList)
-
   // nsDOMCSSValueList
   nsDOMCSSValueList(bool aCommaDelimited, bool aReadonly);
 
   /**
    * Adds a value to this list.
    */
   void AppendCSSValue(already_AddRefed<CSSValue> aValue);
 
@@ -43,25 +40,18 @@ public:
     return mCSSValues.SafeElementAt(aIndex);
   }
 
   uint32_t Length() const
   {
     return mCSSValues.Length();
   }
 
-  nsISupports* GetParentObject()
-  {
-    return nullptr;
-  }
-
-  virtual JSObject *WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
-
-private:
-  ~nsDOMCSSValueList();
+protected:
+  virtual ~nsDOMCSSValueList();
 
   bool                        mCommaDelimited;  // some value lists use a comma
                                                 // as the delimiter, some just use
                                                 // spaces.
 
   bool                        mReadonly;    // Are we read-only?
 
   InfallibleTArray<RefPtr<CSSValue> > mCSSValues;
--- a/layout/style/nsROCSSPrimitiveValue.cpp
+++ b/layout/style/nsROCSSPrimitiveValue.cpp
@@ -3,111 +3,66 @@
 /* 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/. */
 
 /* DOM object representing values in DOM computed style */
 
 #include "nsROCSSPrimitiveValue.h"
 
-#include "mozilla/dom/CSSPrimitiveValueBinding.h"
 #include "nsPresContext.h"
 #include "nsStyleUtil.h"
 #include "nsDOMCSSRGBColor.h"
 #include "nsDOMCSSRect.h"
 #include "nsIURI.h"
 #include "nsError.h"
 
-// There is no CSS_TURN constant on the CSSPrimitiveValue interface,
-// since that unit is newer than DOM Level 2 Style, and CSS OM will
-// probably expose CSS values in some other way in the future.  We
-// use this value in mType for "turn"-unit angles, but we define it
-// here to avoid exposing it to content.
-#define CSS_TURN 30U
-// Likewise we have some internal aliases for CSS_NUMBER that we don't
-// want to expose.
-#define CSS_NUMBER_INT32 31U
-#define CSS_NUMBER_UINT32 32U
-
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsROCSSPrimitiveValue::nsROCSSPrimitiveValue()
-  : CSSValue(), mType(CSSPrimitiveValueBinding::CSS_PX)
+  : CSSValue(), mType(CSS_PX)
 {
   mValue.mAppUnits = 0;
 }
 
 
 nsROCSSPrimitiveValue::~nsROCSSPrimitiveValue()
 {
   Reset();
 }
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsROCSSPrimitiveValue)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsROCSSPrimitiveValue)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsROCSSPrimitiveValue)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, CSSValue)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsROCSSPrimitiveValue)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsROCSSPrimitiveValue)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsROCSSPrimitiveValue)
-  if (tmp->mType == CSSPrimitiveValueBinding::CSS_URI) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mValue.mURI)
-  } else if (tmp->mType == CSSPrimitiveValueBinding::CSS_RGBCOLOR) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mValue.mColor)
-  } else if (tmp->mType == CSSPrimitiveValueBinding::CSS_RECT) {
-    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mValue.mRect)
-  }
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsROCSSPrimitiveValue)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  tmp->Reset();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-JSObject*
-nsROCSSPrimitiveValue::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
-{
-  return dom::CSSPrimitiveValueBinding::Wrap(cx, this, aGivenProto);
-}
-
 nsresult
 nsROCSSPrimitiveValue::GetCssText(nsAString& aCssText)
 {
   nsAutoString tmpStr;
   aCssText.Truncate();
   nsresult result = NS_OK;
 
   switch (mType) {
-    case CSSPrimitiveValueBinding::CSS_PX:
+    case CSS_PX:
       {
         float val = nsPresContext::AppUnitsToFloatCSSPixels(mValue.mAppUnits);
         nsStyleUtil::AppendCSSNumber(val, tmpStr);
         tmpStr.AppendLiteral("px");
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_IDENT:
+    case CSS_IDENT:
       {
         AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(mValue.mKeyword),
                           tmpStr);
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_STRING:
-    case CSSPrimitiveValueBinding::CSS_COUNTER: /* FIXME: COUNTER should use an object */
+    case CSS_STRING:
+    case CSS_COUNTER: /* FIXME: COUNTER should use an object */
       {
         tmpStr.Append(mValue.mString);
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_URI:
+    case CSS_URI:
       {
         if (mValue.mURI) {
           nsAutoCString specUTF8;
           nsresult rv = mValue.mURI->GetSpec(specUTF8);
           NS_ENSURE_SUCCESS(rv, rv);
 
           tmpStr.AssignLiteral("url(");
           nsStyleUtil::AppendEscapedCSSString(NS_ConvertUTF8toUTF16(specUTF8),
@@ -117,69 +72,69 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
           // http://dev.w3.org/csswg/css3-values/#attr defines
           // 'about:invalid' as the default value for url attributes,
           // so let's also use it here as the default computed value
           // for invalid URLs.
           tmpStr.AssignLiteral(u"url(about:invalid)");
         }
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_ATTR:
+    case CSS_ATTR:
       {
         tmpStr.AppendLiteral("attr(");
         tmpStr.Append(mValue.mString);
         tmpStr.Append(char16_t(')'));
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_PERCENTAGE:
+    case CSS_PERCENTAGE:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat * 100, tmpStr);
         tmpStr.Append(char16_t('%'));
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_NUMBER:
+    case CSS_NUMBER:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         break;
       }
     case CSS_NUMBER_INT32:
       {
         tmpStr.AppendInt(mValue.mInt32);
         break;
       }
     case CSS_NUMBER_UINT32:
       {
         tmpStr.AppendInt(mValue.mUint32);
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_DEG:
+    case CSS_DEG:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         tmpStr.AppendLiteral("deg");
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_GRAD:
+    case CSS_GRAD:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         tmpStr.AppendLiteral("grad");
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_RAD:
+    case CSS_RAD:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         tmpStr.AppendLiteral("rad");
         break;
       }
     case CSS_TURN:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         tmpStr.AppendLiteral("turn");
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_RECT:
+    case CSS_RECT:
       {
         NS_ASSERTION(mValue.mRect, "mValue.mRect should never be null");
         NS_NAMED_LITERAL_STRING(comma, ", ");
         nsAutoString sideValue;
         tmpStr.AssignLiteral("rect(");
         // get the top
         result = mValue.mRect->Top()->GetCssText(sideValue);
         if (NS_FAILED(result))
@@ -197,17 +152,17 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
         tmpStr.Append(sideValue + comma);
         // get the left
         result = mValue.mRect->Left()->GetCssText(sideValue);
         if (NS_FAILED(result))
           break;
         tmpStr.Append(sideValue + NS_LITERAL_STRING(")"));
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_RGBCOLOR:
+    case CSS_RGBCOLOR:
       {
         NS_ASSERTION(mValue.mColor, "mValue.mColor should never be null");
         ErrorResult error;
         NS_NAMED_LITERAL_STRING(comma, ", ");
         nsAutoString colorValue;
         if (mValue.mColor->HasAlpha())
           tmpStr.AssignLiteral("rgba(");
         else
@@ -238,34 +193,34 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
             break;
           tmpStr.Append(comma + colorValue);
         }
 
         tmpStr.Append(')');
 
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_S:
+    case CSS_S:
       {
         nsStyleUtil::AppendCSSNumber(mValue.mFloat, tmpStr);
         tmpStr.Append('s');
         break;
       }
-    case CSSPrimitiveValueBinding::CSS_CM:
-    case CSSPrimitiveValueBinding::CSS_MM:
-    case CSSPrimitiveValueBinding::CSS_IN:
-    case CSSPrimitiveValueBinding::CSS_PT:
-    case CSSPrimitiveValueBinding::CSS_PC:
-    case CSSPrimitiveValueBinding::CSS_UNKNOWN:
-    case CSSPrimitiveValueBinding::CSS_EMS:
-    case CSSPrimitiveValueBinding::CSS_EXS:
-    case CSSPrimitiveValueBinding::CSS_MS:
-    case CSSPrimitiveValueBinding::CSS_HZ:
-    case CSSPrimitiveValueBinding::CSS_KHZ:
-    case CSSPrimitiveValueBinding::CSS_DIMENSION:
+    case CSS_CM:
+    case CSS_MM:
+    case CSS_IN:
+    case CSS_PT:
+    case CSS_PC:
+    case CSS_UNKNOWN:
+    case CSS_EMS:
+    case CSS_EXS:
+    case CSS_MS:
+    case CSS_HZ:
+    case CSS_KHZ:
+    case CSS_DIMENSION:
       NS_ERROR("We have a bogus value set.  This should not happen");
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
   if (NS_SUCCEEDED(result)) {
     aCssText.Assign(tmpStr);
   }
 
@@ -282,106 +237,106 @@ void
 nsROCSSPrimitiveValue::SetCssText(const nsAString& aText, ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
 }
 
 uint16_t
 nsROCSSPrimitiveValue::CssValueType() const
 {
-  return CSSValueBinding::CSS_PRIMITIVE_VALUE;
+  return CSSValue::CSS_PRIMITIVE_VALUE;
 }
 
 void
 nsROCSSPrimitiveValue::SetFloatValue(uint16_t aType, float aVal,
                                      ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
 }
 
 float
 nsROCSSPrimitiveValue::GetFloatValue(uint16_t aUnitType, ErrorResult& aRv)
 {
   switch(aUnitType) {
-    case CSSPrimitiveValueBinding::CSS_PX:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_PX:
+      if (mType == CSS_PX) {
         return nsPresContext::AppUnitsToFloatCSSPixels(mValue.mAppUnits);
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_CM:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_CM:
+      if (mType == CSS_PX) {
         return mValue.mAppUnits * CM_PER_INCH_FLOAT /
           nsPresContext::AppUnitsPerCSSInch();
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_MM:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_MM:
+      if (mType == CSS_PX) {
         return mValue.mAppUnits * MM_PER_INCH_FLOAT /
           nsPresContext::AppUnitsPerCSSInch();
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_IN:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_IN:
+      if (mType == CSS_PX) {
         return mValue.mAppUnits / nsPresContext::AppUnitsPerCSSInch();
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_PT:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_PT:
+      if (mType == CSS_PX) {
         return mValue.mAppUnits * POINTS_PER_INCH_FLOAT /
           nsPresContext::AppUnitsPerCSSInch();
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_PC:
-      if (mType == CSSPrimitiveValueBinding::CSS_PX) {
+    case CSS_PC:
+      if (mType == CSS_PX) {
         return mValue.mAppUnits * 6.0f /
           nsPresContext::AppUnitsPerCSSInch();
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_PERCENTAGE:
-      if (mType == CSSPrimitiveValueBinding::CSS_PERCENTAGE) {
+    case CSS_PERCENTAGE:
+      if (mType == CSS_PERCENTAGE) {
         return mValue.mFloat * 100;
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_NUMBER:
-      if (mType == CSSPrimitiveValueBinding::CSS_NUMBER) {
+    case CSS_NUMBER:
+      if (mType == CSS_NUMBER) {
         return mValue.mFloat;
       }
       if (mType == CSS_NUMBER_INT32) {
         return mValue.mInt32;
       }
       if (mType == CSS_NUMBER_UINT32) {
         return mValue.mUint32;
       }
 
       break;
-    case CSSPrimitiveValueBinding::CSS_UNKNOWN:
-    case CSSPrimitiveValueBinding::CSS_EMS:
-    case CSSPrimitiveValueBinding::CSS_EXS:
-    case CSSPrimitiveValueBinding::CSS_DEG:
-    case CSSPrimitiveValueBinding::CSS_RAD:
-    case CSSPrimitiveValueBinding::CSS_GRAD:
-    case CSSPrimitiveValueBinding::CSS_MS:
-    case CSSPrimitiveValueBinding::CSS_S:
-    case CSSPrimitiveValueBinding::CSS_HZ:
-    case CSSPrimitiveValueBinding::CSS_KHZ:
-    case CSSPrimitiveValueBinding::CSS_DIMENSION:
-    case CSSPrimitiveValueBinding::CSS_STRING:
-    case CSSPrimitiveValueBinding::CSS_URI:
-    case CSSPrimitiveValueBinding::CSS_IDENT:
-    case CSSPrimitiveValueBinding::CSS_ATTR:
-    case CSSPrimitiveValueBinding::CSS_COUNTER:
-    case CSSPrimitiveValueBinding::CSS_RECT:
-    case CSSPrimitiveValueBinding::CSS_RGBCOLOR:
+    case CSS_UNKNOWN:
+    case CSS_EMS:
+    case CSS_EXS:
+    case CSS_DEG:
+    case CSS_RAD:
+    case CSS_GRAD:
+    case CSS_MS:
+    case CSS_S:
+    case CSS_HZ:
+    case CSS_KHZ:
+    case CSS_DIMENSION:
+    case CSS_STRING:
+    case CSS_URI:
+    case CSS_IDENT:
+    case CSS_ATTR:
+    case CSS_COUNTER:
+    case CSS_RECT:
+    case CSS_RGBCOLOR:
       break;
   }
 
   aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
   return 0;
 }
 
 void
@@ -390,24 +345,24 @@ nsROCSSPrimitiveValue::SetStringValue(ui
 {
   aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
 }
 
 void
 nsROCSSPrimitiveValue::GetStringValue(nsString& aReturn, ErrorResult& aRv)
 {
   switch (mType) {
-    case CSSPrimitiveValueBinding::CSS_IDENT:
+    case CSS_IDENT:
       CopyUTF8toUTF16(nsCSSKeywords::GetStringValue(mValue.mKeyword), aReturn);
       break;
-    case CSSPrimitiveValueBinding::CSS_STRING:
-    case CSSPrimitiveValueBinding::CSS_ATTR:
+    case CSS_STRING:
+    case CSS_ATTR:
       aReturn.Assign(mValue.mString);
       break;
-    case CSSPrimitiveValueBinding::CSS_URI: {
+    case CSS_URI: {
       nsAutoCString spec;
       if (mValue.mURI) {
         nsresult rv = mValue.mURI->GetSpec(spec);
         if (NS_FAILED(rv)) {
           aRv.Throw(rv);
           return;
         }
       }
@@ -425,43 +380,43 @@ void
 nsROCSSPrimitiveValue::GetCounterValue(ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
 }
 
 nsDOMCSSRect*
 nsROCSSPrimitiveValue::GetRectValue(ErrorResult& aRv)
 {
-  if (mType != CSSPrimitiveValueBinding::CSS_RECT) {
+  if (mType != CSS_RECT) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return nullptr;
   }
 
   NS_ASSERTION(mValue.mRect, "mValue.mRect should never be null");
   return mValue.mRect;
 }
 
 nsDOMCSSRGBColor*
 nsROCSSPrimitiveValue::GetRGBColorValue(ErrorResult& aRv)
 {
-  if (mType != CSSPrimitiveValueBinding::CSS_RGBCOLOR) {
+  if (mType != CSS_RGBCOLOR) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return nullptr;
   }
 
   NS_ASSERTION(mValue.mColor, "mValue.mColor should never be null");
   return mValue.mColor;
 }
 
 void
 nsROCSSPrimitiveValue::SetNumber(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_NUMBER;
+  mType = CSS_NUMBER;
 }
 
 void
 nsROCSSPrimitiveValue::SetNumber(int32_t aValue)
 {
   Reset();
   mValue.mInt32 = aValue;
   mType = CSS_NUMBER_INT32;
@@ -475,188 +430,187 @@ nsROCSSPrimitiveValue::SetNumber(uint32_
   mType = CSS_NUMBER_UINT32;
 }
 
 void
 nsROCSSPrimitiveValue::SetPercent(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_PERCENTAGE;
+  mType = CSS_PERCENTAGE;
 }
 
 void
 nsROCSSPrimitiveValue::SetDegree(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_DEG;
+  mType = CSS_DEG;
 }
 
 void
 nsROCSSPrimitiveValue::SetGrad(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_GRAD;
+  mType = CSS_GRAD;
 }
 
 void
 nsROCSSPrimitiveValue::SetRadian(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_RAD;
+  mType = CSS_RAD;
 }
 
 void
 nsROCSSPrimitiveValue::SetTurn(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
   mType = CSS_TURN;
 }
 
 void
 nsROCSSPrimitiveValue::SetAppUnits(nscoord aValue)
 {
   Reset();
   mValue.mAppUnits = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_PX;
+  mType = CSS_PX;
 }
 
 void
 nsROCSSPrimitiveValue::SetAppUnits(float aValue)
 {
   SetAppUnits(NSToCoordRound(aValue));
 }
 
 void
 nsROCSSPrimitiveValue::SetIdent(nsCSSKeyword aKeyword)
 {
   MOZ_ASSERT(aKeyword != eCSSKeyword_UNKNOWN &&
              0 <= aKeyword && aKeyword < eCSSKeyword_COUNT,
              "bad keyword");
   Reset();
   mValue.mKeyword = aKeyword;
-  mType = CSSPrimitiveValueBinding::CSS_IDENT;
+  mType = CSS_IDENT;
 }
 
 // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
 void
 nsROCSSPrimitiveValue::SetString(const nsACString& aString, uint16_t aType)
 {
   Reset();
   mValue.mString = ToNewUnicode(aString);
   if (mValue.mString) {
     mType = aType;
   } else {
     // XXXcaa We should probably let the caller know we are out of memory
-    mType = CSSPrimitiveValueBinding::CSS_UNKNOWN;
+    mType = CSS_UNKNOWN;
   }
 }
 
 // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
 void
 nsROCSSPrimitiveValue::SetString(const nsAString& aString, uint16_t aType)
 {
   Reset();
   mValue.mString = ToNewUnicode(aString);
   if (mValue.mString) {
     mType = aType;
   } else {
     // XXXcaa We should probably let the caller know we are out of memory
-    mType = CSSPrimitiveValueBinding::CSS_UNKNOWN;
+    mType = CSS_UNKNOWN;
   }
 }
 
 void
 nsROCSSPrimitiveValue::SetURI(nsIURI *aURI)
 {
   Reset();
   mValue.mURI = aURI;
   NS_IF_ADDREF(mValue.mURI);
-  mType = CSSPrimitiveValueBinding::CSS_URI;
+  mType = CSS_URI;
 }
 
 void
 nsROCSSPrimitiveValue::SetColor(nsDOMCSSRGBColor* aColor)
 {
   MOZ_ASSERT(aColor, "Null RGBColor being set!");
 
   Reset();
   mValue.mColor = aColor;
   if (mValue.mColor) {
     NS_ADDREF(mValue.mColor);
-    mType = CSSPrimitiveValueBinding::CSS_RGBCOLOR;
+    mType = CSS_RGBCOLOR;
   }
   else {
-    mType = CSSPrimitiveValueBinding::CSS_UNKNOWN;
+    mType = CSS_UNKNOWN;
   }
 }
 
 void
 nsROCSSPrimitiveValue::SetRect(nsDOMCSSRect* aRect)
 {
   MOZ_ASSERT(aRect, "Null rect being set!");
 
   Reset();
   mValue.mRect = aRect;
   if (mValue.mRect) {
     NS_ADDREF(mValue.mRect);
-    mType = CSSPrimitiveValueBinding::CSS_RECT;
+    mType = CSS_RECT;
   }
   else {
-    mType = CSSPrimitiveValueBinding::CSS_UNKNOWN;
+    mType = CSS_UNKNOWN;
   }
 }
 
 void
 nsROCSSPrimitiveValue::SetTime(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
-  mType = CSSPrimitiveValueBinding::CSS_S;
+  mType = CSS_S;
 }
 
 void
 nsROCSSPrimitiveValue::Reset()
 {
   switch (mType) {
-    case CSSPrimitiveValueBinding::CSS_IDENT:
+    case CSS_IDENT:
       break;
-    case CSSPrimitiveValueBinding::CSS_STRING:
-    case CSSPrimitiveValueBinding::CSS_ATTR:
-    case CSSPrimitiveValueBinding::CSS_COUNTER: // FIXME: Counter should use an object
+    case CSS_STRING:
+    case CSS_ATTR:
+    case CSS_COUNTER: // FIXME: Counter should use an object
       NS_ASSERTION(mValue.mString, "Null string should never happen");
       free(mValue.mString);
       mValue.mString = nullptr;
       break;
-    case CSSPrimitiveValueBinding::CSS_URI:
+    case CSS_URI:
       NS_IF_RELEASE(mValue.mURI);
       break;
-    case CSSPrimitiveValueBinding::CSS_RECT:
+    case CSS_RECT:
       NS_ASSERTION(mValue.mRect, "Null Rect should never happen");
       NS_RELEASE(mValue.mRect);
       break;
-    case CSSPrimitiveValueBinding::CSS_RGBCOLOR:
+    case CSS_RGBCOLOR:
       NS_ASSERTION(mValue.mColor, "Null RGBColor should never happen");
       NS_RELEASE(mValue.mColor);
       break;
   }
 
-  mType = CSSPrimitiveValueBinding::CSS_UNKNOWN;
+  mType = CSS_UNKNOWN;
 }
 
 uint16_t
 nsROCSSPrimitiveValue::PrimitiveType()
 {
   // New value types were introduced but not added to CSS OM.
   // Return CSS_UNKNOWN to avoid exposing CSS_TURN to content.
-  if (mType > CSSPrimitiveValueBinding::CSS_RGBCOLOR) {
-    if (mType == CSS_NUMBER_INT32 ||
-        mType == CSS_NUMBER_UINT32) {
-      return CSSPrimitiveValueBinding::CSS_NUMBER;
+  if (mType > CSS_RGBCOLOR) {
+    if (mType == CSS_NUMBER_INT32 || mType == CSS_NUMBER_UINT32) {
+      return CSS_NUMBER;
     }
-    return CSSPrimitiveValueBinding::CSS_UNKNOWN;
+    return CSS_UNKNOWN;
   }
   return mType;
 }
--- a/layout/style/nsROCSSPrimitiveValue.h
+++ b/layout/style/nsROCSSPrimitiveValue.h
@@ -4,37 +4,63 @@
  * 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/. */
 
 /* DOM object representing values in DOM computed style */
 
 #ifndef nsROCSSPrimitiveValue_h___
 #define nsROCSSPrimitiveValue_h___
 
-#include "mozilla/dom/CSSPrimitiveValueBinding.h"
-#include "mozilla/dom/CSSValueBinding.h"
-
 #include "nsCSSKeywords.h"
 #include "CSSValue.h"
 #include "nsCOMPtr.h"
 #include "nsCoord.h"
 
 class nsIURI;
 class nsDOMCSSRect;
 class nsDOMCSSRGBColor;
 
 /**
  * Read-only CSS primitive value - a DOM object representing values in DOM
  * computed style.
  */
 class nsROCSSPrimitiveValue final : public mozilla::dom::CSSValue
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsROCSSPrimitiveValue)
+  enum : uint16_t {
+    CSS_UNKNOWN,
+    CSS_NUMBER,
+    CSS_PERCENTAGE,
+    CSS_EMS,
+    CSS_EXS,
+    CSS_PX,
+    CSS_CM,
+    CSS_MM,
+    CSS_IN,
+    CSS_PT,
+    CSS_PC,
+    CSS_DEG,
+    CSS_RAD,
+    CSS_GRAD,
+    CSS_MS,
+    CSS_S,
+    CSS_HZ,
+    CSS_KHZ,
+    CSS_DIMENSION,
+    CSS_STRING,
+    CSS_URI,
+    CSS_IDENT,
+    CSS_ATTR,
+    CSS_COUNTER,
+    CSS_RECT,
+    CSS_RGBCOLOR,
+    CSS_TURN,
+    CSS_NUMBER_INT32,
+    CSS_NUMBER_UINT32,
+  };
 
   // CSSValue
   void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) final;
   void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) final;
   uint16_t CssValueType() const final;
 
   // CSSPrimitiveValue
   uint16_t PrimitiveType();
@@ -59,38 +85,27 @@ public:
   void SetDegree(float aValue);
   void SetGrad(float aValue);
   void SetRadian(float aValue);
   void SetTurn(float aValue);
   void SetAppUnits(nscoord aValue);
   void SetAppUnits(float aValue);
   void SetIdent(nsCSSKeyword aKeyword);
   // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
-  void SetString(
-      const nsACString& aString,
-      uint16_t aType = mozilla::dom::CSSPrimitiveValueBinding::CSS_STRING);
+  void SetString(const nsACString& aString, uint16_t aType = CSS_STRING);
   // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
-  void SetString(
-      const nsAString& aString,
-      uint16_t aType = mozilla::dom::CSSPrimitiveValueBinding::CSS_STRING);
+  void SetString(const nsAString& aString, uint16_t aType = CSS_STRING);
   void SetURI(nsIURI *aURI);
   void SetColor(nsDOMCSSRGBColor* aColor);
   void SetRect(nsDOMCSSRect* aRect);
   void SetTime(float aValue);
   void Reset();
 
-  nsISupports* GetParentObject() const
-  {
-    return nullptr;
-  }
-
-  virtual JSObject *WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto) override;
-
-private:
-  ~nsROCSSPrimitiveValue();
+  virtual ~nsROCSSPrimitiveValue();
+protected:
 
   uint16_t mType;
 
   union {
     nscoord         mAppUnits;
     float           mFloat;
     int32_t         mInt32;
     uint32_t        mUint32;
@@ -101,13 +116,13 @@ private:
     nsIURI* MOZ_OWNING_REF mURI;
     nsCSSKeyword    mKeyword;
   } mValue;
 };
 
 inline nsROCSSPrimitiveValue*
 mozilla::dom::CSSValue::AsPrimitiveValue()
 {
-  return CssValueType() == CSSValueBinding::CSS_PRIMITIVE_VALUE ?
-    static_cast<nsROCSSPrimitiveValue*>(this) : nullptr;
+  return CssValueType() == mozilla::dom::CSSValue::CSS_PRIMITIVE_VALUE
+    ? static_cast<nsROCSSPrimitiveValue*>(this) : nullptr;
 }
 
 #endif /* nsROCSSPrimitiveValue_h___ */
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeTelemetry.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeTelemetry.java
@@ -1,121 +1,55 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * vim: ts=4 sw=4 expandtab:
  * 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/. */
 
 package org.mozilla.geckoview;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
 import android.util.Log;
 
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.EventCallback;
 
 /**
  * The telemetry API gives access to telemetry data of the Gecko runtime.
  */
 public final class RuntimeTelemetry {
     private final static String LOGTAG = "GeckoViewTelemetry";
     private final static boolean DEBUG = false;
 
     private final GeckoRuntime mRuntime;
     private final EventDispatcher mEventDispatcher;
 
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ DATASET_BASE, DATASET_EXTENDED })
-    public @interface DatasetType {}
-
-    // Match with nsITelemetry.
-    /**
-     * The base dataset suitable for release builds.
-     */
-    public static final int DATASET_BASE = 0;
-    /**
-     * The extended dataset suitable for pre-release builds.
-     */
-    public static final int DATASET_EXTENDED = 1;
-
-    @IntDef(flag = true,
-            value = { SNAPSHOT_HISTOGRAMS, SNAPSHOT_KEYED_HISTOGRAMS,
-                      SNAPSHOT_SCALARS, SNAPSHOT_KEYED_SCALARS,
-                      SNAPSHOT_ALL })
-    public @interface SnapshotType {}
-
-    // Match with GeckoViewTelemetryController.
-    /**
-     * Adds a "histogram" object entry to the snapshot response.
-     */
-    public static final int SNAPSHOT_HISTOGRAMS = 1 << 0;
-    /**
-     * Adds a "keyedHistogram" object entry to the snapshot response.
-     */
-    public static final int SNAPSHOT_KEYED_HISTOGRAMS = 1 << 1;
-    /**
-     * Adds a "scalars" object entry to the snapshot response.
-     */
-    public static final int SNAPSHOT_SCALARS = 1 << 2;
-    /**
-     * Adds a "keyedScalars" object entry to the snapshot response.
-     */
-    public static final int SNAPSHOT_KEYED_SCALARS = 1 << 3;
-    /**
-     * Adds all snapshot types to the response.
-     */
-    public static final int SNAPSHOT_ALL = (1 << 4) - 1;
-
     /* package */ RuntimeTelemetry(final @NonNull GeckoRuntime runtime) {
         mRuntime = runtime;
         mEventDispatcher = EventDispatcher.getInstance();
     }
 
     /**
      * Retrieve all telemetry snapshots.
+     * The response bundle will contain following snapshots:
+     * <ul>
+     * <li>histograms</li>
+     * <li>keyedHistograms</li>
+     * <li>scalars</li>
+     * <li>keyedScalars</li>
+     * </ul>
      *
-     * @param dataset The dataset type to retreive.
-     *                One of {@link #DATASET_BASE DATASET_*} flags.
      * @param clear Whether the retrieved snapshots should be cleared.
      * @param response Used to return the async response.
      */
     public void getSnapshots(
-          final @DatasetType int dataset,
           final boolean clear,
           final @NonNull GeckoResponse<GeckoBundle> response) {
-        getSnapshots(SNAPSHOT_ALL, dataset, clear, response);
-    }
-
-    /**
-     * Retrieve the requested telemetry snapshots.
-     *
-     * @param types The requested snapshot types.
-     *              One or more of {@link #SNAPSHOT_HISTOGRAMS SNAPSHOT_*} flags.
-     * @param dataset The dataset type to retreive.
-     *                One of {@link #DATASET_BASE DATASET_*} flags.
-     * @param clear Whether the retrieved snapshots should be cleared.
-     * @param response Used to return the async response.
-     */
-    public void getSnapshots(
-          final @SnapshotType int types,
-          final @DatasetType int dataset,
-          final boolean clear,
-          final @NonNull GeckoResponse<GeckoBundle> response) {
-        final GeckoBundle msg = new GeckoBundle(3);
-        msg.putInt("types", types);
-        msg.putInt("dataset", dataset);
+        final GeckoBundle msg = new GeckoBundle(1);
         msg.putBoolean("clear", clear);
 
         mEventDispatcher.dispatch("GeckoView:TelemetrySnapshots", msg,
             new EventCallback() {
                 @Override
                 public void sendSuccess(final Object result) {
                     response.respond((GeckoBundle) result);
                 }
--- a/old-configure.in
+++ b/old-configure.in
@@ -1741,17 +1741,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.37, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.38, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -z "$MOZ_SYSTEM_NSS"; then
    NSS_CFLAGS="-I${DIST}/include/nss"
    case "${OS_ARCH}" in
         # Only few platforms have been tested with GYP
         WINNT|Darwin|Linux|DragonFly|FreeBSD|NetBSD|OpenBSD|SunOS)
             ;;
--- a/python/mozbuild/mozbuild/action/xpidl-process.py
+++ b/python/mozbuild/mozbuild/action/xpidl-process.py
@@ -22,38 +22,39 @@ from xpidl.rust import print_rust_bindin
 from xpidl.rust_macros import print_rust_macros_bindings
 from xpidl.xpidl import IDLParser
 
 from mozbuild.makeutil import Makefile
 from mozbuild.pythonutil import iter_modules_in_path
 from mozbuild.util import FileAvoidWrite
 
 
-def process(input_dir, inc_paths, bindings_conf, cache_dir, header_dir,
-            xpcrs_dir, xpt_dir, deps_dir, module, stems):
+def process(input_dirs, inc_paths, bindings_conf, cache_dir, header_dir,
+            xpcrs_dir, xpt_dir, deps_dir, module, idl_files):
     p = IDLParser(outputdir=cache_dir)
 
     xpts = []
     mk = Makefile()
     rule = mk.create_rule()
 
     glbl = {}
     execfile(bindings_conf, glbl)
     webidlconfig = glbl['DOMInterfaces']
 
     # Write out dependencies for Python modules we import. If this list isn't
     # up to date, we will not re-process XPIDL files if the processor changes.
     rule.add_dependencies(iter_modules_in_path(topsrcdir))
 
-    for stem in stems:
-        path = os.path.join(input_dir, '%s.idl' % stem)
+    for path in idl_files:
+        basename = os.path.basename(path)
+        stem, _ = os.path.splitext(basename)
         idl_data = open(path).read()
 
         idl = p.parse(idl_data, filename=path)
-        idl.resolve([input_dir] + inc_paths, p, webidlconfig)
+        idl.resolve(inc_paths, p, webidlconfig)
 
         header_path = os.path.join(header_dir, '%s.h' % stem)
         rs_rt_path = os.path.join(xpcrs_dir, 'rt', '%s.rs' % stem)
         rs_bt_path = os.path.join(xpcrs_dir, 'bt', '%s.rs' % stem)
 
         xpts.append(jsonxpt.build_typelib(idl))
 
         rule.add_dependencies(idl.deps)
@@ -86,30 +87,32 @@ def process(input_dir, inc_paths, bindin
 def main(argv):
     parser = argparse.ArgumentParser()
     parser.add_argument('--cache-dir',
         help='Directory in which to find or write cached lexer data.')
     parser.add_argument('--depsdir',
         help='Directory in which to write dependency files.')
     parser.add_argument('--bindings-conf',
         help='Path to the WebIDL binding configuration file.')
-    parser.add_argument('inputdir',
-        help='Directory in which to find source .idl files.')
+    parser.add_argument('--input-dir', dest='input_dirs',
+                        action='append', default=[],
+                        help='Directory(ies) in which to find source .idl files.')
     parser.add_argument('headerdir',
         help='Directory in which to write header files.')
     parser.add_argument('xpcrsdir',
         help='Directory in which to write rust xpcom binding files.')
     parser.add_argument('xptdir',
         help='Directory in which to write xpt file.')
     parser.add_argument('module',
         help='Final module name to use for linked output xpt file.')
     parser.add_argument('idls', nargs='+',
-        help='Source .idl file(s). Specified as stems only.')
+        help='Source .idl file(s).')
     parser.add_argument('-I', dest='incpath', action='append', default=[],
         help='Extra directories where to look for included .idl files.')
 
     args = parser.parse_args(argv)
-    process(args.inputdir, args.incpath, args.bindings_conf, args.cache_dir,
+    incpath = [os.path.join(topsrcdir, p) for p in args.incpath]
+    process(args.input_dirs, incpath, args.bindings_conf, args.cache_dir,
         args.headerdir, args.xpcrsdir, args.xptdir, args.depsdir, args.module,
         args.idls)
 
 if __name__ == '__main__':
     main(sys.argv[1:])
--- a/python/mozbuild/mozbuild/backend/common.py
+++ b/python/mozbuild/mozbuild/backend/common.py
@@ -54,38 +54,45 @@ class XPIDLManager(object):
     def __init__(self, config):
         self.config = config
         self.topsrcdir = config.topsrcdir
         self.topobjdir = config.topobjdir
 
         self.idls = {}
         self.modules = {}
 
-    def register_idl(self, idl, allow_existing=False):
+    def register_idl(self, idl):
         """Registers an IDL file with this instance.
 
         The IDL file will be built, installed, etc.
         """
         basename = mozpath.basename(idl.source_path)
+        dirname = mozpath.dirname(idl.source_path)
         root = mozpath.splitext(basename)[0]
         xpt = '%s.xpt' % idl.module
 
         entry = {
             'source': idl.source_path,
             'module': idl.module,
             'basename': basename,
             'root': root,
         }
 
-        if not allow_existing and entry['basename'] in self.idls:
+        if entry['basename'] in self.idls:
             raise Exception('IDL already registered: %s' % entry['basename'])
 
         self.idls[entry['basename']] = entry
-        t = self.modules.setdefault(entry['module'], (idl.install_target, set()))
-        t[1].add(entry['root'])
+        # First element is a set of interface file basenames (no extension).
+        #
+        # Second element is a set of directory names where module IDLs
+        # can be found.  Yes, we have XPIDL modules with files from
+        # multiple directories.
+        t = self.modules.setdefault(entry['module'], (set(), set()))
+        t[0].add(entry['source'])
+        t[1].add(dirname)
 
 class BinariesCollection(object):
     """Tracks state of binaries produced by the build."""
 
     def __init__(self):
         self.shared_libraries = []
         self.programs = []
 
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -1040,48 +1040,50 @@ class RecursiveMakeBackend(CommonBackend
 
     def _handle_idl_manager(self, manager):
         build_files = self._install_manifests['xpidl']
 
         for p in ('Makefile', 'backend.mk', '.deps/.mkdir.done'):
             build_files.add_optional_exists(p)
 
         for idl in manager.idls.values():
-            self._install_manifests['dist_idl'].add_link(idl['source'],
-                idl['basename'])
             self._install_manifests['dist_include'].add_optional_exists('%s.h'
                 % idl['root'])
 
         for module in manager.modules:
             build_files.add_optional_exists(mozpath.join('.deps',
                 '%s.pp' % module))
 
         modules = manager.modules
         xpt_modules = sorted(modules.keys())
 
         mk = Makefile()
+        all_directories = set()
 
         for module in xpt_modules:
-            install_target, sources = modules[module]
+            sources, directories = modules[module]
+            all_directories |= directories
             deps = sorted(sources)
 
             # It may seem strange to have the .idl files listed as
             # prerequisites both here and in the auto-generated .pp files.
             # It is necessary to list them here to handle the case where a
             # new .idl is added to an xpt. If we add a new .idl and nothing
             # else has changed, the new .idl won't be referenced anywhere
             # except in the command invocation. Therefore, the .xpt won't
             # be rebuilt because the dependencies say it is up to date. By
             # listing the .idls here, we ensure the make file has a
             # reference to the new .idl. Since the new .idl presumably has
             # an mtime newer than the .xpt, it will trigger xpt generation.
             mk.add_statement('%s_deps = %s' % (module, ' '.join(deps)))
 
             build_files.add_optional_exists('%s.xpt' % module)
 
+        mk.add_statement('all_idl_dirs = %s' % ' '.join(sorted(all_directories)))
+
         rules = StringIO()
         mk.dump(rules, removal_guard=False)
 
         # Create dependency for output header so we force regeneration if the
         # header was deleted. This ideally should not be necessary. However,
         # some processes (such as PGO at the time this was implemented) wipe
         # out dist/include without regard to our install manifests.
 
--- a/python/mozbuild/mozbuild/backend/tup.py
+++ b/python/mozbuild/mozbuild/backend/tup.py
@@ -791,40 +791,48 @@ class TupBackend(CommonBackend):
 
         dist_idl_backend_file = self._get_backend_file('dist/idl')
         for idl in manager.idls.values():
             dist_idl_backend_file.symlink_rule(idl['source'], output_group=self._installed_idls)
 
         backend_file = self._get_backend_file('xpcom/xpidl')
         backend_file.export_shell()
 
+        all_idl_directories = set()
+        all_idl_directories.update(*map(lambda x: x[1], manager.modules.itervalues()))
+
         all_xpts = []
-        for module, data in sorted(manager.modules.iteritems()):
-            _, idls = data
+        for module, (idls, _) in sorted(manager.modules.iteritems()):
             cmd = [
                 '$(PYTHON_PATH)',
                 '$(PLY_INCLUDE)',
                 '-I$(IDL_PARSER_DIR)',
                 '-I$(IDL_PARSER_CACHE_DIR)',
                 '$(topsrcdir)/python/mozbuild/mozbuild/action/xpidl-process.py',
                 '--cache-dir', '$(IDL_PARSER_CACHE_DIR)',
                 '--bindings-conf', '$(topsrcdir)/dom/bindings/Bindings.conf',
-                '$(DIST)/idl',
+            ]
+
+            for d in all_idl_directories:
+                cmd.extend(['-I', d])
+
+            cmd.extend([
                 '$(DIST)/include',
                 '$(DIST)/xpcrs',
                 '.',
                 module,
-            ]
+            ])
             cmd.extend(sorted(idls))
 
             all_xpts.append('$(MOZ_OBJ_ROOT)/%s/%s.xpt' % (backend_file.relobjdir, module))
             outputs = ['%s.xpt' % module]
-            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/include/%s.h' % f for f in sorted(idls)])
-            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/xpcrs/rt/%s.rs' % f for f in sorted(idls)])
-            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/xpcrs/bt/%s.rs' % f for f in sorted(idls)])
+            stems = sorted(mozpath.splitext(mozpath.basename(idl))[0] for idl in idls)
+            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/include/%s.h' % f for f in stems])
+            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/xpcrs/rt/%s.rs' % f for f in stems])
+            outputs.extend(['$(MOZ_OBJ_ROOT)/dist/xpcrs/bt/%s.rs' % f for f in stems])
             backend_file.rule(
                 inputs=[
                     '$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidllex.py',
                     '$(MOZ_OBJ_ROOT)/xpcom/idl-parser/xpidl/xpidlyacc.py',
                     self._installed_idls,
                 ],
                 display='XPIDL %s' % module,
                 cmd=cmd,
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -683,24 +683,18 @@ class TestRecursiveMakeBackend(BackendTe
 
     def test_xpidl_generation(self):
         """Ensure xpidl files and directories are written out."""
         env = self._consume('xpidl', RecursiveMakeBackend)
 
         # Install manifests should contain entries.
         install_dir = mozpath.join(env.topobjdir, '_build_manifests',
             'install')
-        self.assertTrue(os.path.isfile(mozpath.join(install_dir, 'dist_idl')))
         self.assertTrue(os.path.isfile(mozpath.join(install_dir, 'xpidl')))
 
-        m = InstallManifest(path=mozpath.join(install_dir, 'dist_idl'))
-        self.assertEqual(len(m), 2)
-        self.assertIn('bar.idl', m)
-        self.assertIn('foo.idl', m)
-
         m = InstallManifest(path=mozpath.join(install_dir, 'xpidl'))
         self.assertIn('.deps/my_module.pp', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'xpidl'))
         self.assertIn('my_module.xpt', m)
 
         m = InstallManifest(path=mozpath.join(install_dir, 'dist_include'))
         self.assertIn('foo.h', m)
--- a/taskcluster/docker/diffoscope/Dockerfile
+++ b/taskcluster/docker/diffoscope/Dockerfile
@@ -23,17 +23,17 @@ CMD ["/bin/bash", "--login"]
 RUN for s in debian_stretch debian_stretch-updates debian-security_stretch/updates; do \
       echo "deb [check-valid-until=no] http://snapshot.debian.org/archive/${s%_*}/20171222T153610Z/ ${s#*_} main"; \
     done > /etc/apt/sources.list
 
 RUN apt-get update -q && \
     apt-get install -yyq diffoscope libc++abi1 locales python3-setuptools python2.7 python-pip git && \
     sed -i '/en_US.UTF-8/s/^# *//' /etc/locale.gen && \
     locale-gen && \
-    git clone https://anonscm.debian.org/git/reproducible/diffoscope.git /tmp/diffoscope && \
+    git clone https://salsa.debian.org/reproducible-builds/diffoscope.git /tmp/diffoscope && \
     git -C /tmp/diffoscope checkout 202caf9d5d134e95f870d5f19f89511d635c27e4 && \
     (cd /tmp/diffoscope && python3 setup.py install ) && \
     rm -rf /tmp/diffoscope && \
     apt-get clean
 
 # %include taskcluster/scripts/run-task
 COPY topsrcdir/taskcluster/scripts/run-task /builds/worker/bin/run-task
 
--- a/taskcluster/docker/recipes/ubuntu1604-test-system-setup.sh
+++ b/taskcluster/docker/recipes/ubuntu1604-test-system-setup.sh
@@ -51,16 +51,17 @@ apt_packages+=('libxxf86vm1')
 apt_packages+=('llvm')
 apt_packages+=('llvm-dev')
 apt_packages+=('llvm-runtime')
 apt_packages+=('nano')
 apt_packages+=('net-tools')
 apt_packages+=('pulseaudio')
 apt_packages+=('pulseaudio-module-bluetooth')
 apt_packages+=('pulseaudio-module-gconf')
+apt_packages+=('qemu-kvm')
 apt_packages+=('rlwrap')
 apt_packages+=('screen')
 apt_packages+=('software-properties-common')
 apt_packages+=('sudo')
 apt_packages+=('tar')
 apt_packages+=('ttf-dejavu')
 apt_packages+=('ubuntu-desktop')
 apt_packages+=('unzip')
--- a/taskcluster/scripts/run-task
+++ b/taskcluster/scripts/run-task
@@ -492,16 +492,21 @@ def main(args):
             uid = user.pw_uid
             gid = group.gr_gid
         else:
             print('error: run-task must be run as root on POSIX platforms')
             return 1
     else:
         uid = gid = gids = None
 
+    if os.path.exists("/dev/kvm"):
+        # Ensure kvm permissions for worker, required for Android x86
+        st = os.stat("/dev/kvm")
+        os.chmod("/dev/kvm", st.st_mode | 0666)
+
     # Validate caches.
     #
     # Taskgraph should pass in a list of paths that are caches via an
     # environment variable (which we don't want to pass down to child
     # processes).
 
     if 'TASKCLUSTER_CACHES' in os.environ:
         caches = os.environ['TASKCLUSTER_CACHES'].split(';')
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-025.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-025.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-026.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-026.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-028.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-028.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-029.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-029.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-031.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-031.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-032.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-032.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-033.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-033.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-034.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-034.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-035.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-035.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-036.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-036.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-372.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-372.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-373.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-373.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-375.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-375.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-376.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-376.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-378.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-378.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-379.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-379.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-380.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-380.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-381.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-381.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-382.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-382.xht]
-  expected: FAIL
deleted file mode 100644
--- a/testing/web-platform/meta/css/CSS2/selectors/first-letter-punctuation-383.xht.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[first-letter-punctuation-383.xht]
-  expected: FAIL
--- a/toolkit/components/telemetry/geckoview/GeckoViewTelemetryController.jsm
+++ b/toolkit/components/telemetry/geckoview/GeckoViewTelemetryController.jsm
@@ -14,62 +14,46 @@ XPCOMUtils.defineLazyModuleGetters(this,
 });
 
 GeckoViewUtils.initLogging("GeckoView.TelemetryController", this);
 
 var EXPORTED_SYMBOLS = ["GeckoViewTelemetryController"];
 
 /* global debug warn */
 
-/**
- * Telemetry snapshot API adaptors used to retrieve one or more snapshots
- * for GeckoView:TelemetrySnapshots requests.
- * Match with RuntimeTelemetry.SNAPSHOT_* and nsITelemetry.idl.
- */
-const TelemetrySnapshots = [
-  {
-    type: "histograms",
-    flag: (1 << 0),
-    get: (dataset, clear) => Services.telemetry.snapshotHistograms(
-                               dataset, false, clear)
-  },
-  {
-    type: "keyedHistograms",
-    flag: (1 << 1),
-    get: (dataset, clear) => Services.telemetry.snapshotKeyedHistograms(
-                               dataset, false, clear)
-  },
-  {
-    type: "scalars",
-    flag: (1 << 2),
-    get: (dataset, clear) => Services.telemetry.snapshotScalars(
-                               dataset, clear)
-  },
-  {
-    type: "keyedScalars",
-    flag: (1 << 3),
-    get: (dataset, clear) => Services.telemetry.snapshotKeyedScalars(
-                               dataset, clear)
-  },
-];
+// Persistent data loading topic - see TelemetryGeckoViewPersistence.cpp.
+const LOAD_COMPLETE_TOPIC = "internal-telemetry-geckoview-load-complete";
 
 const GeckoViewTelemetryController = {
   /**
    * Setup the Telemetry recording flags. This must be called
    * in all the processes that need to collect Telemetry.
    */
   setup() {
-    debug `setup`;
-
     TelemetryUtils.setTelemetryRecordingFlags();
 
-    debug `setup - canRecordPrereleaseData ${Services.telemetry.canRecordPrereleaseData
-          }, canRecordReleaseData ${Services.telemetry.canRecordReleaseData}`;
+    debug `setup -
+           canRecordPrereleaseData ${Services.telemetry.canRecordPrereleaseData},
+           canRecordReleaseData ${Services.telemetry.canRecordReleaseData}`;
 
     if (GeckoViewUtils.IS_PARENT_PROCESS) {
+      // Prevent dispatching snapshots before persistent data has been loaded.
+      this._loadComplete = new Promise(resolve => {
+        Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+          if (aTopic !== LOAD_COMPLETE_TOPIC) {
+            warn `Received unexpected topic ${aTopic}`;
+            return;
+          }
+          debug `observed ${aTopic} - ready to handle telemetry requests`;
+          // Loading data has completed, discard this observer.
+          Services.obs.removeObserver(observer, LOAD_COMPLETE_TOPIC);
+          resolve();
+        }, LOAD_COMPLETE_TOPIC);
+      });
+
       try {
         EventDispatcher.instance.registerListener(this, [
           "GeckoView:TelemetrySnapshots",
         ]);
       } catch (e) {
         warn `Failed registering GeckoView:TelemetrySnapshots listener: ${e}`;
       }
     }
@@ -86,28 +70,50 @@ const GeckoViewTelemetryController = {
   onEvent(aEvent, aData, aCallback) {
     debug `onEvent: aEvent=${aEvent}, aData=${aData}`;
 
     if (aEvent !== "GeckoView:TelemetrySnapshots") {
       warn `Received unexpected event ${aEvent}`;
       return;
     }
 
-    const { clear, types, dataset } = aData;
-    let snapshots = {};
+    // Handle this request when loading has completed.
+    this._loadComplete.then(() => this.retrieveSnapshots(aData.clear, aCallback));
+  },
+
+  /**
+   * Retrieve snapshots and forward them to the callback.
+   *
+   * @param aClear True if snapshot data should be cleared after retrieving.
+   * @param aCallback Callback implementing nsIAndroidEventCallback.
+   */
+  retrieveSnapshots(aClear, aCallback) {
+    debug `retrieveSnapshots`;
+
+    // Selecting the opt-in dataset will ensure that we retrieve opt-in probes
+    // (iff canRecordPreRelease == true) and opt-out probes
+    // (iff canRecordRelease == true) if they are being recorded.
+    const dataset = Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN;
 
-    // Iterate over all snapshot types, retreive and assemble results.
-    for (const tel of TelemetrySnapshots) {
-      if ((tel.flag & types) == 0) {
-        // This snapshot type has not been requested.
-        continue;
-      }
-      const snapshot = tel.get(dataset, clear);
-      if (!snapshot) {
-        aCallback.onError(`Failed retrieving ${tel.type} snapshot!`);
-        return;
-      }
-      snapshots[tel.type] = snapshot;
+    const snapshots = {
+      histograms: Services.telemetry.snapshotHistograms(
+                      dataset, /* subsession */ false, /* clear */ false),
+      keyedHistograms: Services.telemetry.snapshotKeyedHistograms(
+                           dataset, /* subsession */ false, /* clear */ false),
+      scalars: Services.telemetry.snapshotScalars(
+                   dataset, /* clear */ false),
+      keyedScalars: Services.telemetry.snapshotKeyedScalars(
+                        dataset, /* clear */ false),
+    };
+
+    if (!snapshots.histograms || !snapshots.keyedHistograms ||
+        !snapshots.scalars || !snapshots.keyedScalars) {
+      aCallback.onError(`Failed retrieving snapshots!`);
+      return;
+    }
+
+    if (aClear) {
+      Services.telemetry.clearProbes();
     }
 
     aCallback.onSuccess(snapshots);
   },
 };
--- a/xpcom/base/nsISupportsImpl.h
+++ b/xpcom/base/nsISupportsImpl.h
@@ -34,22 +34,16 @@
                 "Make this class's destructor non-public");
 
 inline nsISupports*
 ToSupports(nsISupports* aSupports)
 {
   return aSupports;
 }
 
-inline nsISupports*
-ToCanonicalSupports(nsISupports* aSupports)
-{
-  return nullptr;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Macros to help detect thread-safety:
 
 #ifdef MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED
 
 #include "prthread.h" /* needed for thread-safety checks */
 
 class nsAutoOwningThread
--- a/xpcom/components/nsIClassInfo.idl
+++ b/xpcom/components/nsIClassInfo.idl
@@ -56,22 +56,16 @@ interface nsIClassInfo : nsISupports
      */
     const uint32_t SINGLETON            = 1 << 0;
     const uint32_t THREADSAFE           = 1 << 1;
     const uint32_t MAIN_THREAD_ONLY     = 1 << 2;
     const uint32_t DOM_OBJECT           = 1 << 3;
     const uint32_t PLUGIN_OBJECT        = 1 << 4;
     const uint32_t SINGLETON_CLASSINFO  = 1 << 5;
 
-    /**
-     * 'flags' attribute bitflag: whether objects of this type implement
-     * nsIContent.
-     */
-    const uint32_t CONTENT_NODE         = 1 << 6;
-
     // The high order bit is RESERVED for consumers of these flags. 
     // No implementor of this interface should ever return flags 
     // with this bit set.
     const uint32_t RESERVED             = 1 << 31;
 
 
     readonly attribute uint32_t flags;
 
--- a/xpcom/xpidl/Makefile.in
+++ b/xpcom/xpidl/Makefile.in
@@ -1,10 +1,9 @@
 # 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/.
 
 export::
-	$(call py_action,process_install_manifest,--track install-xpidl.track $(DIST)/idl $(DEPTH)/_build_manifests/install/dist_idl)
 	$(call SUBMAKE,xpidl,$(DEPTH)/config/makefiles/xpidl)
 
 clean clobber realclean clobber_all distclean::
 	$(call SUBMAKE,$@,$(DEPTH)/config/makefiles/xpidl)