merge mozilla-inbound to mozilla-central on a CLOSED TREE
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 21 Oct 2015 15:32:33 +0200
changeset 268679 473aefe5bd85
parent 268630 d43374e69703 (current diff)
parent 268678 749c557fab38 (diff)
child 268680 2d3fd51c4182
child 268697 a9f84167b319
child 268769 ab8d2508c6ea
child 268826 03549a077855
push id29559
push usercbook@mozilla.com
push dateWed, 21 Oct 2015 13:33:00 +0000
treeherdermozilla-central@473aefe5bd85 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone44.0a1
first release with
nightly linux32
473aefe5bd85 / 44.0a1 / 20151021064220 / files
nightly linux64
473aefe5bd85 / 44.0a1 / 20151021064220 / files
nightly mac
473aefe5bd85 / 44.0a1 / 20151021064220 / files
nightly win32
473aefe5bd85 / 44.0a1 / 20151021065025 / files
nightly win64
473aefe5bd85 / 44.0a1 / 20151021064220 / 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 on a CLOSED TREE
testing/web-platform/meta/XMLHttpRequest/send-content-type-string.htm.ini
testing/web-platform/meta/XMLHttpRequest/send-entity-body-document.htm.ini
testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data
testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js
testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html
xpcom/glue/Logging.h
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -653,22 +653,25 @@ AccessibleWrap::get_accFocus(
   //              and does not contain a child that has the keyboard focus.
   // VT_I4:       lVal is CHILDID_SELF. The object itself has the keyboard focus.
   // VT_I4:       lVal contains the child ID of the child element with the keyboard focus.
   // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
   //              for the child object with the keyboard focus.
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  // TODO make this work with proxies.
-  if (IsProxy())
-    return E_NOTIMPL;
+  // Return the current IAccessible child that has focus
+  Accessible* focusedAccessible;
+  if (IsProxy()) {
+    ProxyAccessible* proxy = Proxy()->FocusedChild();
+    focusedAccessible = proxy ? WrapperFor(proxy) : nullptr;
+  } else {
+    focusedAccessible = FocusedChild();
+  }
 
-  // Return the current IAccessible child that has focus
-  Accessible* focusedAccessible = FocusedChild();
   if (focusedAccessible == this) {
     pvarChild->vt = VT_I4;
     pvarChild->lVal = CHILDID_SELF;
   }
   else if (focusedAccessible) {
     pvarChild->vt = VT_DISPATCH;
     pvarChild->pdispVal = NativeAccessible(focusedAccessible);
   }
@@ -825,17 +828,27 @@ AccessibleWrap::get_accSelection(VARIANT
     return CO_E_OBJNOTCONNECTED;
 
   // TODO make this work with proxies.
   if (IsProxy())
     return E_NOTIMPL;
 
   if (IsSelect()) {
     nsAutoTArray<Accessible*, 10> selectedItems;
-    SelectedItems(&selectedItems);
+    if (IsProxy()) {
+      nsTArray<ProxyAccessible*> proxies;
+      Proxy()->SelectedItems(&proxies);
+
+      uint32_t selectedCount = proxies.Length();
+      for (uint32_t i = 0; i < selectedCount; i++) {
+        selectedItems.AppendElement(WrapperFor(proxies[i]));
+      }
+    } else {
+      SelectedItems(&selectedItems);
+    }
 
     // 1) Create and initialize the enumeration
     RefPtr<AccessibleEnumerator> pEnum = new AccessibleEnumerator(selectedItems);
     pvarChildren->vt = VT_UNKNOWN;    // this must be VT_UNKNOWN for an IEnumVARIANT
     NS_ADDREF(pvarChildren->punkVal = pEnum);
   }
   return S_OK;
 
@@ -859,22 +872,23 @@ AccessibleWrap::get_accDefaultAction(
 
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
 
   if (xpAccessible->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  // TODO make this work with proxies.
-  if (xpAccessible->IsProxy())
-    return E_NOTIMPL;
+  nsAutoString defaultAction;
+  if (xpAccessible->IsProxy()) {
+    xpAccessible->Proxy()->ActionNameAt(0, defaultAction);
+  } else {
+    xpAccessible->ActionNameAt(0, defaultAction);
+  }
 
-  nsAutoString defaultAction;
-  xpAccessible->ActionNameAt(0, defaultAction);
   *pszDefaultAction = ::SysAllocStringLen(defaultAction.get(),
                                           defaultAction.Length());
   return *pszDefaultAction ? S_OK : E_OUTOFMEMORY;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
@@ -890,33 +904,52 @@ AccessibleWrap::accSelect(
   // currently only handle focus and selection
   Accessible* xpAccessible = GetXPAccessibleFor(varChild);
   if (!xpAccessible)
     return E_INVALIDARG;
 
   if (xpAccessible->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  // TODO make this work with proxies.
-  if (xpAccessible->IsProxy())
-    return E_NOTIMPL;
+  if (flagsSelect & SELFLAG_TAKEFOCUS) {
+    if (xpAccessible->IsProxy()) {
+      xpAccessible->Proxy()->TakeFocus();
+    } else {
+      xpAccessible->TakeFocus();
+    }
 
-  if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION))
-  {
-    if (flagsSelect & SELFLAG_TAKEFOCUS)
-      xpAccessible->TakeFocus();
+    return S_OK;
+  }
+
+  if (flagsSelect & SELFLAG_TAKESELECTION) {
+    if (xpAccessible->IsProxy()) {
+      xpAccessible->Proxy()->TakeSelection();
+    } else {
+      xpAccessible->TakeSelection();
+    }
 
-    if (flagsSelect & SELFLAG_TAKESELECTION)
-      xpAccessible->TakeSelection();
+    return S_OK;
+  }
+
+  if (flagsSelect & SELFLAG_ADDSELECTION) {
+    if (xpAccessible->IsProxy()) {
+      xpAccessible->Proxy()->SetSelected(true);
+    } else {
+      xpAccessible->SetSelected(true);
+    }
 
-    if (flagsSelect & SELFLAG_ADDSELECTION)
-      xpAccessible->SetSelected(true);
+    return S_OK;
+  }
 
-    if (flagsSelect & SELFLAG_REMOVESELECTION)
+  if (flagsSelect & SELFLAG_REMOVESELECTION) {
+    if (xpAccessible->IsProxy()) {
+      xpAccessible->Proxy()->SetSelected(false);
+    } else {
       xpAccessible->SetSelected(false);
+    }
 
     return S_OK;
   }
 
   return E_FAIL;
 
   A11Y_TRYBLOCK_END
 }
@@ -1058,21 +1091,25 @@ AccessibleWrap::accHitTest(
   if (!pvarChild)
     return E_INVALIDARG;
 
   VariantInit(pvarChild);
 
   if (IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
-  // TODO make this work with proxies.
-  if (IsProxy())
-    return E_NOTIMPL;
-
-  Accessible* accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
+  Accessible* accessible = nullptr;
+  if (IsProxy()) {
+    ProxyAccessible* proxy = Proxy()->ChildAtPoint(xLeft, yTop, eDirectChild);
+    if (proxy) {
+      accessible = WrapperFor(proxy);
+    }
+  } else {
+    accessible = ChildAtPoint(xLeft, yTop, eDirectChild);
+  }
 
   // if we got a child
   if (accessible) {
     // if the child is us
     if (accessible == this) {
       pvarChild->vt = VT_I4;
       pvarChild->lVal = CHILDID_SELF;
     } else { // its not create an Accessible for it.
@@ -1102,17 +1139,17 @@ AccessibleWrap::accDoDefaultAction(
   if (!xpAccessible)
     return E_INVALIDARG;
 
   if (xpAccessible->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
   // TODO make this work with proxies.
   if (xpAccessible->IsProxy())
-    return E_NOTIMPL;
+    return xpAccessible->Proxy()->DoAction(0) ? S_OK : E_INVALIDARG;
 
   return xpAccessible->DoAction(0) ? S_OK : E_INVALIDARG;
 
   A11Y_TRYBLOCK_END
 }
 
 STDMETHODIMP
 AccessibleWrap::put_accName(
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1441,21 +1441,29 @@ pref("security.onecrl.maximum_staleness_
 // Override the Gecko-default value of false for Firefox.
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
 // before content.
 pref("dom.debug.propagate_gesture_events_through_content", false);
 
 // The request URL of the GeoLocation backend.
+#ifdef RELEASE_BUILD
+pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%");
+#else
 pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
+#endif
 
 #ifdef XP_MACOSX
+#ifdef RELEASE_BUILD
+pref("geo.provider.use_corelocation", false);
+#else
 pref("geo.provider.use_corelocation", true);
 #endif
+#endif
 
 #ifdef XP_WIN
 pref("geo.provider.ms-windows-location", false);
 #endif
 
 // Necko IPC security checks only needed for app isolation for cookies/cache/etc:
 // currently irrelevant for desktop e10s
 pref("network.disable.ipc.security", true);
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -2057,502 +2057,16 @@ FragmentOrElement::GetChildArray(uint32_
 }
 
 int32_t
 FragmentOrElement::IndexOf(const nsINode* aPossibleChild) const
 {
   return mAttrsAndChildren.IndexOfChild(aPossibleChild);
 }
 
-// Try to keep the size of StringBuilder close to a jemalloc bucket size.
-#define STRING_BUFFER_UNITS 1020
-
-namespace {
-
-// We put StringBuilder in the anonymous namespace to prevent anything outside
-// this file from accidentally being linked against it.
-
-class StringBuilder
-{
-private:
-  class Unit
-  {
-  public:
-    Unit() : mAtom(nullptr), mType(eUnknown), mLength(0)
-    {
-      MOZ_COUNT_CTOR(StringBuilder::Unit);
-    }
-    ~Unit()
-    {
-      if (mType == eString || mType == eStringWithEncode) {
-        delete mString;
-      }
-      MOZ_COUNT_DTOR(StringBuilder::Unit);
-    }
-
-    enum Type
-    {
-      eUnknown,
-      eAtom,
-      eString,
-      eStringWithEncode,
-      eLiteral,
-      eTextFragment,
-      eTextFragmentWithEncode,
-    };
-
-    union
-    {
-      nsIAtom*              mAtom;
-      const char*           mLiteral;
-      nsAutoString*         mString;
-      const nsTextFragment* mTextFragment;
-    };
-    Type     mType;
-    uint32_t mLength;
-  };
-public:
-  StringBuilder() : mLast(this), mLength(0)
-  {
-    MOZ_COUNT_CTOR(StringBuilder);
-  }
-
-  ~StringBuilder()
-  {
-    MOZ_COUNT_DTOR(StringBuilder);
-  }
-
-  void Append(nsIAtom* aAtom)
-  {
-    Unit* u = AddUnit();
-    u->mAtom = aAtom;
-    u->mType = Unit::eAtom;
-    uint32_t len = aAtom->GetLength();
-    u->mLength = len;
-    mLength += len;
-  }
-
-  template<int N>
-  void Append(const char (&aLiteral)[N])
-  {
-    Unit* u = AddUnit();
-    u->mLiteral = aLiteral;
-    u->mType = Unit::eLiteral;
-    uint32_t len = N - 1;
-    u->mLength = len;
-    mLength += len;
-  }
-
-  template<int N>
-  void Append(char (&aLiteral)[N])
-  {
-    Unit* u = AddUnit();
-    u->mLiteral = aLiteral;
-    u->mType = Unit::eLiteral;
-    uint32_t len = N - 1;
-    u->mLength = len;
-    mLength += len;
-  }
-
-  void Append(const nsAString& aString)
-  {
-    Unit* u = AddUnit();
-    u->mString = new nsAutoString(aString);
-    u->mType = Unit::eString;
-    uint32_t len = aString.Length();
-    u->mLength = len;
-    mLength += len;
-  }
-
-  void Append(nsAutoString* aString)
-  {
-    Unit* u = AddUnit();
-    u->mString = aString;
-    u->mType = Unit::eString;
-    uint32_t len = aString->Length();
-    u->mLength = len;
-    mLength += len;
-  }
-
-  void AppendWithAttrEncode(nsAutoString* aString, uint32_t aLen)
-  {
-    Unit* u = AddUnit();
-    u->mString = aString;
-    u->mType = Unit::eStringWithEncode;
-    u->mLength = aLen;
-    mLength += aLen;
-  }
-
-  void Append(const nsTextFragment* aTextFragment)
-  {
-    Unit* u = AddUnit();
-    u->mTextFragment = aTextFragment;
-    u->mType = Unit::eTextFragment;
-    uint32_t len = aTextFragment->GetLength();
-    u->mLength = len;
-    mLength += len;
-  }
-
-  void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t aLen)
-  {
-    Unit* u = AddUnit();
-    u->mTextFragment = aTextFragment;
-    u->mType = Unit::eTextFragmentWithEncode;
-    u->mLength = aLen;
-    mLength += aLen;
-  }
-
-  bool ToString(nsAString& aOut)
-  {
-    if (!aOut.SetCapacity(mLength, fallible)) {
-      return false;
-    }
-
-    for (StringBuilder* current = this; current; current = current->mNext) {
-      uint32_t len = current->mUnits.Length();
-      for (uint32_t i = 0; i < len; ++i) {
-        Unit& u = current->mUnits[i];
-        switch (u.mType) {
-          case Unit::eAtom:
-            aOut.Append(nsDependentAtomString(u.mAtom));
-            break;
-          case Unit::eString:
-            aOut.Append(*(u.mString));
-            break;
-          case Unit::eStringWithEncode:
-            EncodeAttrString(*(u.mString), aOut);
-            break;
-          case Unit::eLiteral:
-            aOut.AppendASCII(u.mLiteral, u.mLength);
-            break;
-          case Unit::eTextFragment:
-            u.mTextFragment->AppendTo(aOut);
-            break;
-          case Unit::eTextFragmentWithEncode:
-            EncodeTextFragment(u.mTextFragment, aOut);
-            break;
-          default:
-            MOZ_CRASH("Unknown unit type?");
-        }
-      }
-    }
-    return true;
-  }
-private:
-  Unit* AddUnit()
-  {
-    if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
-      new StringBuilder(this);
-    }
-    return mLast->mUnits.AppendElement();
-  }
-
-  explicit StringBuilder(StringBuilder* aFirst)
-  : mLast(nullptr), mLength(0)
-  {
-    MOZ_COUNT_CTOR(StringBuilder);
-    aFirst->mLast->mNext = this;
-    aFirst->mLast = this;
-  }
-
-  void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
-  {
-    const char16_t* c = aValue.BeginReading();
-    const char16_t* end = aValue.EndReading();
-    while (c < end) {
-      switch (*c) {
-      case '"':
-        aOut.AppendLiteral("&quot;");
-        break;
-      case '&':
-        aOut.AppendLiteral("&amp;");
-        break;
-      case 0x00A0:
-        aOut.AppendLiteral("&nbsp;");
-        break;
-      default:
-        aOut.Append(*c);
-        break;
-      }
-      ++c;
-    }
-  }
-
-  void EncodeTextFragment(const nsTextFragment* aValue, nsAString& aOut)
-  {
-    uint32_t len = aValue->GetLength();
-    if (aValue->Is2b()) {
-      const char16_t* data = aValue->Get2b();
-      for (uint32_t i = 0; i < len; ++i) {
-        const char16_t c = data[i];
-        switch (c) {
-          case '<':
-            aOut.AppendLiteral("&lt;");
-            break;
-          case '>':
-            aOut.AppendLiteral("&gt;");
-            break;
-          case '&':
-            aOut.AppendLiteral("&amp;");
-            break;
-          case 0x00A0:
-            aOut.AppendLiteral("&nbsp;");
-            break;
-          default:
-            aOut.Append(c);
-            break;
-        }
-      }
-    } else {
-      const char* data = aValue->Get1b();
-      for (uint32_t i = 0; i < len; ++i) {
-        const unsigned char c = data[i];
-        switch (c) {
-          case '<':
-            aOut.AppendLiteral("&lt;");
-            break;
-          case '>':
-            aOut.AppendLiteral("&gt;");
-            break;
-          case '&':
-            aOut.AppendLiteral("&amp;");
-            break;
-          case 0x00A0:
-            aOut.AppendLiteral("&nbsp;");
-            break;
-          default:
-            aOut.Append(c);
-            break;
-        }
-      }
-    }
-  }
-
-  nsAutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
-  nsAutoPtr<StringBuilder>                mNext;
-  StringBuilder*                          mLast;
-  // mLength is used only in the first StringBuilder object in the linked list.
-  uint32_t                                mLength;
-};
-
-} // namespace
-
-static void
-AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
-{
-  uint32_t extraSpaceNeeded = 0;
-  uint32_t len = aText->GetLength();
-  if (aText->Is2b()) {
-    const char16_t* data = aText->Get2b();
-    for (uint32_t i = 0; i < len; ++i) {
-      const char16_t c = data[i];
-      switch (c) {
-        case '<':
-          extraSpaceNeeded += ArrayLength("&lt;") - 2;
-          break;
-        case '>':
-          extraSpaceNeeded += ArrayLength("&gt;") - 2;
-          break;
-        case '&':
-          extraSpaceNeeded += ArrayLength("&amp;") - 2;
-          break;
-        case 0x00A0:
-          extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
-          break;
-        default:
-          break;
-      }
-    }
-  } else {
-    const char* data = aText->Get1b();
-    for (uint32_t i = 0; i < len; ++i) {
-      const unsigned char c = data[i];
-      switch (c) {
-        case '<':
-          extraSpaceNeeded += ArrayLength("&lt;") - 2;
-          break;
-        case '>':
-          extraSpaceNeeded += ArrayLength("&gt;") - 2;
-          break;
-        case '&':
-          extraSpaceNeeded += ArrayLength("&amp;") - 2;
-          break;
-        case 0x00A0:
-          extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
-          break;
-        default:
-          break;
-      }
-    }
-  }
-
-  if (extraSpaceNeeded) {
-    aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded);
-  } else {
-    aBuilder.Append(aText);
-  }
-}
-
-static void
-AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder)
-{
-  const char16_t* c = aValue->BeginReading();
-  const char16_t* end = aValue->EndReading();
-
-  uint32_t extraSpaceNeeded = 0;
-  while (c < end) {
-    switch (*c) {
-      case '"':
-        extraSpaceNeeded += ArrayLength("&quot;") - 2;
-        break;
-      case '&':
-        extraSpaceNeeded += ArrayLength("&amp;") - 2;
-        break;
-      case 0x00A0:
-        extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
-        break;
-      default:
-        break;
-    }
-    ++c;
-  }
-
-  if (extraSpaceNeeded) {
-    aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded);
-  } else {
-    aBuilder.Append(aValue);
-  }
-}
-
-static void
-StartElement(Element* aContent, StringBuilder& aBuilder)
-{
-  nsIAtom* localName = aContent->NodeInfo()->NameAtom();
-  int32_t tagNS = aContent->GetNameSpaceID();
-
-  aBuilder.Append("<");
-  if (aContent->IsHTMLElement() || aContent->IsSVGElement() ||
-      aContent->IsMathMLElement()) {
-    aBuilder.Append(localName);
-  } else {
-    aBuilder.Append(aContent->NodeName());
-  }
-
-  int32_t count = aContent->GetAttrCount();
-  for (int32_t i = count; i > 0;) {
-    --i;
-    const nsAttrName* name = aContent->GetAttrNameAt(i);
-    int32_t attNs = name->NamespaceID();
-    nsIAtom* attName = name->LocalName();
-
-    // Filter out any attribute starting with [-|_]moz
-    nsDependentAtomString attrNameStr(attName);
-    if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
-        StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
-      continue;
-    }
-
-    nsAutoString* attValue = new nsAutoString();
-    aContent->GetAttr(attNs, attName, *attValue);
-
-    // Filter out special case of <br type="_moz*"> used by the editor.
-    // Bug 16988.  Yuck.
-    if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
-        attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
-        StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
-      delete attValue;
-      continue;
-    }
-
-    aBuilder.Append(" ");
-
-    if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
-        (attNs == kNameSpaceID_XMLNS &&
-         attName == nsGkAtoms::xmlns)) {
-      // Nothing else required
-    } else if (attNs == kNameSpaceID_XML) {
-      aBuilder.Append("xml:");
-    } else if (attNs == kNameSpaceID_XMLNS) {
-      aBuilder.Append("xmlns:");
-    } else if (attNs == kNameSpaceID_XLink) {
-      aBuilder.Append("xlink:");
-    } else {
-      nsIAtom* prefix = name->GetPrefix();
-      if (prefix) {
-        aBuilder.Append(prefix);
-        aBuilder.Append(":");
-      }
-    }
-
-    aBuilder.Append(attName);
-    aBuilder.Append("=\"");
-    AppendEncodedAttributeValue(attValue, aBuilder);
-    aBuilder.Append("\"");
-  }
-
-  aBuilder.Append(">");
-
-  /*
-  // Per HTML spec we should append one \n if the first child of
-  // pre/textarea/listing is a textnode and starts with a \n.
-  // But because browsers haven't traditionally had that behavior,
-  // we're not changing our behavior either - yet.
-  if (aContent->IsHTMLElement()) {
-    if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
-        localName == nsGkAtoms::listing) {
-      nsIContent* fc = aContent->GetFirstChild();
-      if (fc &&
-          (fc->NodeType() == nsIDOMNode::TEXT_NODE ||
-           fc->NodeType() == nsIDOMNode::CDATA_SECTION_NODE)) {
-        const nsTextFragment* text = fc->GetText();
-        if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
-          aBuilder.Append("\n");
-        }
-      }
-    }
-  }*/
-}
-
-static inline bool
-ShouldEscape(nsIContent* aParent)
-{
-  if (!aParent || !aParent->IsHTMLElement()) {
-    return true;
-  }
-
-  static const nsIAtom* nonEscapingElements[] = {
-    nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
-    nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
-    nsGkAtoms::plaintext,
-    // Per the current spec noscript should be escaped in case
-    // scripts are disabled or if document doesn't have
-    // browsing context. However the latter seems to be a spec bug
-    // and Gecko hasn't traditionally done the former.
-    nsGkAtoms::noscript
-  };
-  static mozilla::BloomFilter<12, nsIAtom> sFilter;
-  static bool sInitialized = false;
-  if (!sInitialized) {
-    sInitialized = true;
-    for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
-      sFilter.add(nonEscapingElements[i]);
-    }
-  }
-
-  nsIAtom* tag = aParent->NodeInfo()->NameAtom();
-  if (sFilter.mightContain(tag)) {
-    for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
-      if (tag == nonEscapingElements[i]) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
 static inline bool
 IsVoidTag(nsIAtom* aTag)
 {
   static const nsIAtom* voidElements[] = {
     nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
     nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
     nsGkAtoms::embed, nsGkAtoms::frame,
     nsGkAtoms::hr, nsGkAtoms::img, nsGkAtoms::input,
@@ -2575,146 +2089,31 @@ IsVoidTag(nsIAtom* aTag)
       if (aTag == voidElements[i]) {
         return true;
       }
     }
   }
   return false;
 }
 
-static inline bool
-IsVoidTag(Element* aElement)
-{
-  if (!aElement->IsHTMLElement()) {
-    return false;
-  }
-  return IsVoidTag(aElement->NodeInfo()->NameAtom());
-}
-
 /* static */
 bool
 FragmentOrElement::IsHTMLVoid(nsIAtom* aLocalName)
 {
   return aLocalName && IsVoidTag(aLocalName);
 }
 
-static bool
-Serialize(FragmentOrElement* aRoot, bool aDescendentsOnly, nsAString& aOut)
-{
-  nsINode* current = aDescendentsOnly ?
-    nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : aRoot;
-
-  if (!current) {
-    return true;
-  }
-
-  StringBuilder builder;
-  nsIContent* next;
-  while (true) {
-    bool isVoid = false;
-    switch (current->NodeType()) {
-      case nsIDOMNode::ELEMENT_NODE: {
-        Element* elem = current->AsElement();
-        StartElement(elem, builder);
-        isVoid = IsVoidTag(elem);
-        if (!isVoid &&
-            (next = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) {
-          current = next;
-          continue;
-        }
-        break;
-      }
-
-      case nsIDOMNode::TEXT_NODE:
-      case nsIDOMNode::CDATA_SECTION_NODE: {
-        const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText();
-        nsIContent* parent = current->GetParent();
-        if (ShouldEscape(parent)) {
-          AppendEncodedCharacters(text, builder);
-        } else {
-          builder.Append(text);
-        }
-        break;
-      }
-
-      case nsIDOMNode::COMMENT_NODE: {
-        builder.Append("<!--");
-        builder.Append(static_cast<nsIContent*>(current)->GetText());
-        builder.Append("-->");
-        break;
-      }
-
-      case nsIDOMNode::DOCUMENT_TYPE_NODE: {
-        builder.Append("<!DOCTYPE ");
-        builder.Append(current->NodeName());
-        builder.Append(">");
-        break;
-      }
-
-      case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
-        builder.Append("<?");
-        builder.Append(current->NodeName());
-        builder.Append(" ");
-        builder.Append(static_cast<nsIContent*>(current)->GetText());
-        builder.Append(">");
-        break;
-      }
-    }
-
-    while (true) {
-      if (!isVoid && current->NodeType() == nsIDOMNode::ELEMENT_NODE) {
-        builder.Append("</");
-        nsIContent* elem = static_cast<nsIContent*>(current);
-        if (elem->IsHTMLElement() || elem->IsSVGElement() ||
-            elem->IsMathMLElement()) {
-          builder.Append(elem->NodeInfo()->NameAtom());
-        } else {
-          builder.Append(current->NodeName());
-        }
-        builder.Append(">");
-      }
-      isVoid = false;
-
-      if (current == aRoot) {
-        return builder.ToString(aOut);
-      }
-
-      if ((next = current->GetNextSibling())) {
-        current = next;
-        break;
-      }
-
-      current = current->GetParentNode();
-
-      // Handle template element. If the parent is a template's content,
-      // then adjust the parent to be the template element.
-      if (current != aRoot &&
-          current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
-        DocumentFragment* frag = static_cast<DocumentFragment*>(current);
-        nsIContent* fragHost = frag->GetHost();
-        if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
-          current = fragHost;
-        }
-      }
-
-      if (aDescendentsOnly && current == aRoot) {
-        return builder.ToString(aOut);
-      }
-    }
-  }
-}
-
 void
 FragmentOrElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
 {
   aMarkup.Truncate();
 
   nsIDocument* doc = OwnerDoc();
   if (IsInHTMLDocument()) {
-    Serialize(this, !aIncludeSelf, aMarkup);
+    nsContentUtils::SerializeNodeToMarkup(this, !aIncludeSelf, aMarkup);
     return;
   }
 
   nsAutoString contentType;
   doc->GetContentType(contentType);
   bool tryToCacheEncoder = !aIncludeSelf;
 
   nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
--- a/dom/base/nsContentIterator.cpp
+++ b/dom/base/nsContentIterator.cpp
@@ -43,21 +43,31 @@ static bool
 NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
                        nsINode* aStartNode, int32_t aStartOffset,
                        nsINode* aEndNode, int32_t aEndOffset)
 {
   if (!aStartNode || !aEndNode || !aNode) {
     return false;
   }
 
-  // If a chardata node contains an end point of the traversal range, it is
+  // If a leaf node contains an end point of the traversal range, it is
   // always in the traversal range.
-  if (aNode->IsNodeOfType(nsINode::eDATA_NODE) &&
-      (aNode == aStartNode || aNode == aEndNode)) {
-    return true;
+  if (aNode == aStartNode || aNode == aEndNode) {
+    if (aNode->IsNodeOfType(nsINode::eDATA_NODE)) {
+      return true; // text node or something
+    }
+    if (!aNode->HasChildren()) {
+      MOZ_ASSERT(aNode != aStartNode || !aStartOffset,
+        "aStartNode doesn't have children and not a data node, "
+        "aStartOffset should be 0");
+      MOZ_ASSERT(aNode != aEndNode || !aEndOffset,
+        "aStartNode doesn't have children and not a data node, "
+        "aStartOffset should be 0");
+      return true;
+    }
   }
 
   nsINode* parent = aNode->GetParentNode();
   if (!parent) {
     return false;
   }
 
   int32_t indx = parent->IndexOf(aNode);
@@ -336,22 +346,24 @@ nsContentIterator::Init(nsIDOMRange* aDO
     // XXXbz no children might also just mean no children.  So I'm not
     // sure what that comment above is talking about.
 
     if (mPre) {
       // XXX: In the future, if start offset is after the last
       //      character in the cdata node, should we set mFirst to
       //      the next sibling?
 
-      if (!startIsData) {
+      // If the node has no child, the child may be <br> or something.
+      // So, we shouldn't skip the empty node if the start offset is 0.
+      // In other words, if the offset is 1, the node should be ignored.
+      if (!startIsData && startIndx) {
         mFirst = GetNextSibling(startNode);
 
         // Does mFirst node really intersect the range?  The range could be
         // 'degenerate', i.e., not collapsed but still contain no content.
-
         if (mFirst && !NodeIsInTraversalRange(mFirst, mPre, startNode,
                                               startIndx, endNode, endIndx)) {
           mFirst = nullptr;
         }
       } else {
         mFirst = startNode->AsContent();
       }
     } else {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -192,16 +192,17 @@
 #include "nsXULPopupManager.h"
 #include "xpcprivate.h" // nsXPConnect
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsContentTypeParser.h"
 #include "nsICookiePermission.h"
 #include "mozIThirdPartyUtil.h"
 #include "nsICookieService.h"
 #include "mozilla/EnumSet.h"
+#include "mozilla/BloomFilter.h"
 
 #include "nsIBidiKeyboard.h"
 
 #if defined(XP_WIN)
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 #endif
 
@@ -8254,8 +8255,614 @@ nsContentUtils::InternalStorageAllowedFo
       // for non-cookie storage types, this may change.
 
       return StorageAccess::eDeny;
     }
   }
 
   return access;
 }
+
+namespace {
+
+// We put StringBuilder in the anonymous namespace to prevent anything outside
+// this file from accidentally being linked against it.
+
+class StringBuilder
+{
+private:
+  // Try to keep the size of StringBuilder close to a jemalloc bucket size.
+  static const uint32_t STRING_BUFFER_UNITS = 1020;
+  class Unit
+  {
+  public:
+    Unit() : mAtom(nullptr), mType(eUnknown), mLength(0)
+    {
+      MOZ_COUNT_CTOR(StringBuilder::Unit);
+    }
+    ~Unit()
+    {
+      if (mType == eString || mType == eStringWithEncode) {
+        delete mString;
+      }
+      MOZ_COUNT_DTOR(StringBuilder::Unit);
+    }
+
+    enum Type
+    {
+      eUnknown,
+      eAtom,
+      eString,
+      eStringWithEncode,
+      eLiteral,
+      eTextFragment,
+      eTextFragmentWithEncode,
+    };
+
+    union
+    {
+      nsIAtom*              mAtom;
+      const char*           mLiteral;
+      nsAutoString*         mString;
+      const nsTextFragment* mTextFragment;
+    };
+    Type     mType;
+    uint32_t mLength;
+  };
+public:
+  StringBuilder() : mLast(this), mLength(0)
+  {
+    MOZ_COUNT_CTOR(StringBuilder);
+  }
+
+  ~StringBuilder()
+  {
+    MOZ_COUNT_DTOR(StringBuilder);
+  }
+
+  void Append(nsIAtom* aAtom)
+  {
+    Unit* u = AddUnit();
+    u->mAtom = aAtom;
+    u->mType = Unit::eAtom;
+    uint32_t len = aAtom->GetLength();
+    u->mLength = len;
+    mLength += len;
+  }
+
+  template<int N>
+  void Append(const char (&aLiteral)[N])
+  {
+    Unit* u = AddUnit();
+    u->mLiteral = aLiteral;
+    u->mType = Unit::eLiteral;
+    uint32_t len = N - 1;
+    u->mLength = len;
+    mLength += len;
+  }
+
+  template<int N>
+  void Append(char (&aLiteral)[N])
+  {
+    Unit* u = AddUnit();
+    u->mLiteral = aLiteral;
+    u->mType = Unit::eLiteral;
+    uint32_t len = N - 1;
+    u->mLength = len;
+    mLength += len;
+  }
+
+  void Append(const nsAString& aString)
+  {
+    Unit* u = AddUnit();
+    u->mString = new nsAutoString(aString);
+    u->mType = Unit::eString;
+    uint32_t len = aString.Length();
+    u->mLength = len;
+    mLength += len;
+  }
+
+  void Append(nsAutoString* aString)
+  {
+    Unit* u = AddUnit();
+    u->mString = aString;
+    u->mType = Unit::eString;
+    uint32_t len = aString->Length();
+    u->mLength = len;
+    mLength += len;
+  }
+
+  void AppendWithAttrEncode(nsAutoString* aString, uint32_t aLen)
+  {
+    Unit* u = AddUnit();
+    u->mString = aString;
+    u->mType = Unit::eStringWithEncode;
+    u->mLength = aLen;
+    mLength += aLen;
+  }
+
+  void Append(const nsTextFragment* aTextFragment)
+  {
+    Unit* u = AddUnit();
+    u->mTextFragment = aTextFragment;
+    u->mType = Unit::eTextFragment;
+    uint32_t len = aTextFragment->GetLength();
+    u->mLength = len;
+    mLength += len;
+  }
+
+  void AppendWithEncode(const nsTextFragment* aTextFragment, uint32_t aLen)
+  {
+    Unit* u = AddUnit();
+    u->mTextFragment = aTextFragment;
+    u->mType = Unit::eTextFragmentWithEncode;
+    u->mLength = aLen;
+    mLength += aLen;
+  }
+
+  bool ToString(nsAString& aOut)
+  {
+    if (!aOut.SetCapacity(mLength, fallible)) {
+      return false;
+    }
+
+    for (StringBuilder* current = this; current; current = current->mNext) {
+      uint32_t len = current->mUnits.Length();
+      for (uint32_t i = 0; i < len; ++i) {
+        Unit& u = current->mUnits[i];
+        switch (u.mType) {
+          case Unit::eAtom:
+            aOut.Append(nsDependentAtomString(u.mAtom));
+            break;
+          case Unit::eString:
+            aOut.Append(*(u.mString));
+            break;
+          case Unit::eStringWithEncode:
+            EncodeAttrString(*(u.mString), aOut);
+            break;
+          case Unit::eLiteral:
+            aOut.AppendASCII(u.mLiteral, u.mLength);
+            break;
+          case Unit::eTextFragment:
+            u.mTextFragment->AppendTo(aOut);
+            break;
+          case Unit::eTextFragmentWithEncode:
+            EncodeTextFragment(u.mTextFragment, aOut);
+            break;
+          default:
+            MOZ_CRASH("Unknown unit type?");
+        }
+      }
+    }
+    return true;
+  }
+private:
+  Unit* AddUnit()
+  {
+    if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
+      new StringBuilder(this);
+    }
+    return mLast->mUnits.AppendElement();
+  }
+
+  explicit StringBuilder(StringBuilder* aFirst)
+  : mLast(nullptr), mLength(0)
+  {
+    MOZ_COUNT_CTOR(StringBuilder);
+    aFirst->mLast->mNext = this;
+    aFirst->mLast = this;
+  }
+
+  void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
+  {
+    const char16_t* c = aValue.BeginReading();
+    const char16_t* end = aValue.EndReading();
+    while (c < end) {
+      switch (*c) {
+      case '"':
+        aOut.AppendLiteral("&quot;");
+        break;
+      case '&':
+        aOut.AppendLiteral("&amp;");
+        break;
+      case 0x00A0:
+        aOut.AppendLiteral("&nbsp;");
+        break;
+      default:
+        aOut.Append(*c);
+        break;
+      }
+      ++c;
+    }
+  }
+
+  void EncodeTextFragment(const nsTextFragment* aValue, nsAString& aOut)
+  {
+    uint32_t len = aValue->GetLength();
+    if (aValue->Is2b()) {
+      const char16_t* data = aValue->Get2b();
+      for (uint32_t i = 0; i < len; ++i) {
+        const char16_t c = data[i];
+        switch (c) {
+          case '<':
+            aOut.AppendLiteral("&lt;");
+            break;
+          case '>':
+            aOut.AppendLiteral("&gt;");
+            break;
+          case '&':
+            aOut.AppendLiteral("&amp;");
+            break;
+          case 0x00A0:
+            aOut.AppendLiteral("&nbsp;");
+            break;
+          default:
+            aOut.Append(c);
+            break;
+        }
+      }
+    } else {
+      const char* data = aValue->Get1b();
+      for (uint32_t i = 0; i < len; ++i) {
+        const unsigned char c = data[i];
+        switch (c) {
+          case '<':
+            aOut.AppendLiteral("&lt;");
+            break;
+          case '>':
+            aOut.AppendLiteral("&gt;");
+            break;
+          case '&':
+            aOut.AppendLiteral("&amp;");
+            break;
+          case 0x00A0:
+            aOut.AppendLiteral("&nbsp;");
+            break;
+          default:
+            aOut.Append(c);
+            break;
+        }
+      }
+    }
+  }
+
+  nsAutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
+  nsAutoPtr<StringBuilder>                mNext;
+  StringBuilder*                          mLast;
+  // mLength is used only in the first StringBuilder object in the linked list.
+  uint32_t                                mLength;
+};
+
+} // namespace
+
+static void
+AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
+{
+  uint32_t extraSpaceNeeded = 0;
+  uint32_t len = aText->GetLength();
+  if (aText->Is2b()) {
+    const char16_t* data = aText->Get2b();
+    for (uint32_t i = 0; i < len; ++i) {
+      const char16_t c = data[i];
+      switch (c) {
+        case '<':
+          extraSpaceNeeded += ArrayLength("&lt;") - 2;
+          break;
+        case '>':
+          extraSpaceNeeded += ArrayLength("&gt;") - 2;
+          break;
+        case '&':
+          extraSpaceNeeded += ArrayLength("&amp;") - 2;
+          break;
+        case 0x00A0:
+          extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
+          break;
+        default:
+          break;
+      }
+    }
+  } else {
+    const char* data = aText->Get1b();
+    for (uint32_t i = 0; i < len; ++i) {
+      const unsigned char c = data[i];
+      switch (c) {
+        case '<':
+          extraSpaceNeeded += ArrayLength("&lt;") - 2;
+          break;
+        case '>':
+          extraSpaceNeeded += ArrayLength("&gt;") - 2;
+          break;
+        case '&':
+          extraSpaceNeeded += ArrayLength("&amp;") - 2;
+          break;
+        case 0x00A0:
+          extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
+          break;
+        default:
+          break;
+      }
+    }
+  }
+
+  if (extraSpaceNeeded) {
+    aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded);
+  } else {
+    aBuilder.Append(aText);
+  }
+}
+
+static void
+AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder)
+{
+  const char16_t* c = aValue->BeginReading();
+  const char16_t* end = aValue->EndReading();
+
+  uint32_t extraSpaceNeeded = 0;
+  while (c < end) {
+    switch (*c) {
+      case '"':
+        extraSpaceNeeded += ArrayLength("&quot;") - 2;
+        break;
+      case '&':
+        extraSpaceNeeded += ArrayLength("&amp;") - 2;
+        break;
+      case 0x00A0:
+        extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
+        break;
+      default:
+        break;
+    }
+    ++c;
+  }
+
+  if (extraSpaceNeeded) {
+    aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded);
+  } else {
+    aBuilder.Append(aValue);
+  }
+}
+
+static void
+StartElement(Element* aContent, StringBuilder& aBuilder)
+{
+  nsIAtom* localName = aContent->NodeInfo()->NameAtom();
+  int32_t tagNS = aContent->GetNameSpaceID();
+
+  aBuilder.Append("<");
+  if (aContent->IsHTMLElement() || aContent->IsSVGElement() ||
+      aContent->IsMathMLElement()) {
+    aBuilder.Append(localName);
+  } else {
+    aBuilder.Append(aContent->NodeName());
+  }
+
+  int32_t count = aContent->GetAttrCount();
+  for (int32_t i = count; i > 0;) {
+    --i;
+    const nsAttrName* name = aContent->GetAttrNameAt(i);
+    int32_t attNs = name->NamespaceID();
+    nsIAtom* attName = name->LocalName();
+
+    // Filter out any attribute starting with [-|_]moz
+    nsDependentAtomString attrNameStr(attName);
+    if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
+        StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
+      continue;
+    }
+
+    nsAutoString* attValue = new nsAutoString();
+    aContent->GetAttr(attNs, attName, *attValue);
+
+    // Filter out special case of <br type="_moz*"> used by the editor.
+    // Bug 16988.  Yuck.
+    if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
+        attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
+        StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
+      delete attValue;
+      continue;
+    }
+
+    aBuilder.Append(" ");
+
+    if (MOZ_LIKELY(attNs == kNameSpaceID_None) ||
+        (attNs == kNameSpaceID_XMLNS &&
+         attName == nsGkAtoms::xmlns)) {
+      // Nothing else required
+    } else if (attNs == kNameSpaceID_XML) {
+      aBuilder.Append("xml:");
+    } else if (attNs == kNameSpaceID_XMLNS) {
+      aBuilder.Append("xmlns:");
+    } else if (attNs == kNameSpaceID_XLink) {
+      aBuilder.Append("xlink:");
+    } else {
+      nsIAtom* prefix = name->GetPrefix();
+      if (prefix) {
+        aBuilder.Append(prefix);
+        aBuilder.Append(":");
+      }
+    }
+
+    aBuilder.Append(attName);
+    aBuilder.Append("=\"");
+    AppendEncodedAttributeValue(attValue, aBuilder);
+    aBuilder.Append("\"");
+  }
+
+  aBuilder.Append(">");
+
+  /*
+  // Per HTML spec we should append one \n if the first child of
+  // pre/textarea/listing is a textnode and starts with a \n.
+  // But because browsers haven't traditionally had that behavior,
+  // we're not changing our behavior either - yet.
+  if (aContent->IsHTMLElement()) {
+    if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
+        localName == nsGkAtoms::listing) {
+      nsIContent* fc = aContent->GetFirstChild();
+      if (fc &&
+          (fc->NodeType() == nsIDOMNode::TEXT_NODE ||
+           fc->NodeType() == nsIDOMNode::CDATA_SECTION_NODE)) {
+        const nsTextFragment* text = fc->GetText();
+        if (text && text->GetLength() && text->CharAt(0) == char16_t('\n')) {
+          aBuilder.Append("\n");
+        }
+      }
+    }
+  }*/
+}
+
+static inline bool
+ShouldEscape(nsIContent* aParent)
+{
+  if (!aParent || !aParent->IsHTMLElement()) {
+    return true;
+  }
+
+  static const nsIAtom* nonEscapingElements[] = {
+    nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
+    nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
+    nsGkAtoms::plaintext,
+    // Per the current spec noscript should be escaped in case
+    // scripts are disabled or if document doesn't have
+    // browsing context. However the latter seems to be a spec bug
+    // and Gecko hasn't traditionally done the former.
+    nsGkAtoms::noscript
+  };
+  static mozilla::BloomFilter<12, nsIAtom> sFilter;
+  static bool sInitialized = false;
+  if (!sInitialized) {
+    sInitialized = true;
+    for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
+      sFilter.add(nonEscapingElements[i]);
+    }
+  }
+
+  nsIAtom* tag = aParent->NodeInfo()->NameAtom();
+  if (sFilter.mightContain(tag)) {
+    for (uint32_t i = 0; i < ArrayLength(nonEscapingElements); ++i) {
+      if (tag == nonEscapingElements[i]) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+static inline bool
+IsVoidTag(Element* aElement)
+{
+  if (!aElement->IsHTMLElement()) {
+    return false;
+  }
+  return FragmentOrElement::IsHTMLVoid(aElement->NodeInfo()->NameAtom());
+}
+
+bool
+nsContentUtils::SerializeNodeToMarkup(nsINode* aRoot,
+                                      bool aDescendentsOnly,
+                                      nsAString& aOut)
+{
+  // If you pass in a DOCUMENT_NODE, you must pass aDescendentsOnly as true
+  MOZ_ASSERT(aDescendentsOnly ||
+             aRoot->NodeType() != nsIDOMNode::DOCUMENT_NODE);
+
+  nsINode* current = aDescendentsOnly ?
+    nsNodeUtils::GetFirstChildOfTemplateOrNode(aRoot) : aRoot;
+
+  if (!current) {
+    return true;
+  }
+
+  StringBuilder builder;
+  nsIContent* next;
+  while (true) {
+    bool isVoid = false;
+    switch (current->NodeType()) {
+      case nsIDOMNode::ELEMENT_NODE: {
+        Element* elem = current->AsElement();
+        StartElement(elem, builder);
+        isVoid = IsVoidTag(elem);
+        if (!isVoid &&
+            (next = nsNodeUtils::GetFirstChildOfTemplateOrNode(current))) {
+          current = next;
+          continue;
+        }
+        break;
+      }
+
+      case nsIDOMNode::TEXT_NODE:
+      case nsIDOMNode::CDATA_SECTION_NODE: {
+        const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText();
+        nsIContent* parent = current->GetParent();
+        if (ShouldEscape(parent)) {
+          AppendEncodedCharacters(text, builder);
+        } else {
+          builder.Append(text);
+        }
+        break;
+      }
+
+      case nsIDOMNode::COMMENT_NODE: {
+        builder.Append("<!--");
+        builder.Append(static_cast<nsIContent*>(current)->GetText());
+        builder.Append("-->");
+        break;
+      }
+
+      case nsIDOMNode::DOCUMENT_TYPE_NODE: {
+        builder.Append("<!DOCTYPE ");
+        builder.Append(current->NodeName());
+        builder.Append(">");
+        break;
+      }
+
+      case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
+        builder.Append("<?");
+        builder.Append(current->NodeName());
+        builder.Append(" ");
+        builder.Append(static_cast<nsIContent*>(current)->GetText());
+        builder.Append(">");
+        break;
+      }
+    }
+
+    while (true) {
+      if (!isVoid && current->NodeType() == nsIDOMNode::ELEMENT_NODE) {
+        builder.Append("</");
+        nsIContent* elem = static_cast<nsIContent*>(current);
+        if (elem->IsHTMLElement() || elem->IsSVGElement() ||
+            elem->IsMathMLElement()) {
+          builder.Append(elem->NodeInfo()->NameAtom());
+        } else {
+          builder.Append(current->NodeName());
+        }
+        builder.Append(">");
+      }
+      isVoid = false;
+
+      if (current == aRoot) {
+        return builder.ToString(aOut);
+      }
+
+      if ((next = current->GetNextSibling())) {
+        current = next;
+        break;
+      }
+
+      current = current->GetParentNode();
+
+      // Handle template element. If the parent is a template's content,
+      // then adjust the parent to be the template element.
+      if (current != aRoot &&
+          current->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE) {
+        DocumentFragment* frag = static_cast<DocumentFragment*>(current);
+        nsIContent* fragHost = frag->GetHost();
+        if (fragHost && nsNodeUtils::IsTemplateElement(fragHost)) {
+          current = fragHost;
+        }
+      }
+
+      if (aDescendentsOnly && current == aRoot) {
+        return builder.ToString(aOut);
+      }
+    }
+  }
+}
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -2556,16 +2556,23 @@ public:
 
   /*
    * Checks if storage for the given principal is permitted by the user's
    * preferences. The caller is assumed to not be a third-party iframe.
    * (if that is possible, the caller should use StorageAllowedForWindow)
    */
   static StorageAccess StorageAllowedForPrincipal(nsIPrincipal* aPrincipal);
 
+  /*
+   * Serializes a HTML nsINode into its markup representation.
+   */
+  static bool SerializeNodeToMarkup(nsINode* aRoot,
+                                    bool aDescendentsOnly,
+                                    nsAString& aOut);
+
 private:
   static bool InitializeEventTable();
 
   static nsresult EnsureStringBundle(PropertiesFile aFile);
 
   static bool CanCallerAccess(nsIPrincipal* aSubjectPrincipal,
                                 nsIPrincipal* aPrincipal);
 
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -2306,37 +2306,55 @@ nsXMLHttpRequest::ChangeStateToDone()
   }
 }
 
 static nsresult
 GetRequestBody(nsIDOMDocument* aDoc, nsIInputStream** aResult,
                uint64_t* aContentLength, nsACString& aContentType,
                nsACString& aCharset)
 {
-  aContentType.AssignLiteral("application/xml");
   nsCOMPtr<nsIDocument> doc(do_QueryInterface(aDoc));
   NS_ENSURE_STATE(doc);
   aCharset.AssignLiteral("UTF-8");
 
   nsresult rv;
-  nsCOMPtr<nsIDOMSerializer> serializer =
-    do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   nsCOMPtr<nsIStorageStream> storStream;
   rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIOutputStream> output;
   rv = storStream->GetOutputStream(0, getter_AddRefs(output));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Make sure to use the encoding we'll send
-  rv = serializer->SerializeToStream(aDoc, output, aCharset);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (doc->IsHTMLDocument()) {
+    aContentType.AssignLiteral("text/html");
+
+    nsString serialized;
+    if (!nsContentUtils::SerializeNodeToMarkup(doc, true, serialized)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+    NS_ConvertUTF16toUTF8 utf8Serialized(serialized);
+
+    uint32_t written;
+    rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    MOZ_ASSERT(written == utf8Serialized.Length());
+  } else {
+    aContentType.AssignLiteral("application/xml");
+
+    nsCOMPtr<nsIDOMSerializer> serializer =
+      do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Make sure to use the encoding we'll send
+    rv = serializer->SerializeToStream(aDoc, output, aCharset);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+  }
 
   output->Close();
 
   uint32_t length;
   rv = storStream->GetLength(&length);
   NS_ENSURE_SUCCESS(rv, rv);
   *aContentLength = length;
 
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -4843,16 +4843,19 @@ HTMLInputElement::IsFilesAndDirectoriesS
 
 void
 HTMLInputElement::ChooseDirectory(ErrorResult& aRv)
 {
   if (mType != NS_FORM_INPUT_FILE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
+  // Script can call this method directly, so even though we don't show the
+  // "Pick Folder..." button on platforms that don't have a directory picker
+  // we have to redirect to the file picker here.
   InitFilePicker(
 #if defined(ANDROID) || defined(MOZ_B2G)
                  // No native directory picker - redirect to plain file picker
                  FILE_PICKER_FILE
 #else
                  FILE_PICKER_DIRECTORY
 #endif
                  );
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -108,18 +108,16 @@ public:
       sUniqueInstance = nullptr;
     }
   }
 };
 
 StaticRefPtr<MediaMemoryTracker> MediaMemoryTracker::sUniqueInstance;
 
 #if defined(PR_LOGGING)
-PRLogModuleInfo* gStateWatchingLog;
-PRLogModuleInfo* gMozPromiseLog;
 PRLogModuleInfo* gMediaTimerLog;
 PRLogModuleInfo* gMediaSampleLog;
 #endif
 
 void
 MediaDecoder::InitStatics()
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/webm/WebMDemuxer.cpp
+++ b/dom/media/webm/WebMDemuxer.cpp
@@ -814,19 +814,18 @@ WebMTrackDemuxer::Seek(media::TimeUnit a
 
   media::TimeUnit seekTime = aTime;
   mSamples.Reset();
   mParent->SeekInternal(aTime);
   mParent->GetNextPacket(mType, &mSamples);
 
   // Check what time we actually seeked to.
   if (mSamples.GetSize() > 0) {
-    RefPtr<MediaRawData> sample(mSamples.PopFront());
+    const RefPtr<MediaRawData>& sample = mSamples.First();
     seekTime = media::TimeUnit::FromMicroseconds(sample->mTime);
-    mSamples.PushFront(sample);
   }
   SetNextKeyFrameTime();
 
   return SeekPromise::CreateAndResolve(seekTime, __func__);
 }
 
 RefPtr<MediaRawData>
 WebMTrackDemuxer::NextSample()
@@ -871,50 +870,50 @@ WebMTrackDemuxer::SetNextKeyFrameTime()
     return;
   }
 
   int64_t frameTime = -1;
 
   mNextKeyframeTime.reset();
 
   MediaRawDataQueue skipSamplesQueue;
-  RefPtr<MediaRawData> sample;
   bool foundKeyframe = false;
   while (!foundKeyframe && mSamples.GetSize()) {
-    sample = mSamples.PopFront();
+    RefPtr<MediaRawData> sample = mSamples.PopFront();
     if (sample->mKeyframe) {
       frameTime = sample->mTime;
       foundKeyframe = true;
     }
-    skipSamplesQueue.Push(sample);
+    skipSamplesQueue.Push(sample.forget());
   }
   Maybe<int64_t> startTime;
   if (skipSamplesQueue.GetSize()) {
-    sample = skipSamplesQueue.PopFront();
+    const RefPtr<MediaRawData>& sample = skipSamplesQueue.First();
     startTime.emplace(sample->mTimecode);
-    skipSamplesQueue.PushFront(sample);
   }
   // Demux and buffer frames until we find a keyframe.
+  RefPtr<MediaRawData> sample;
   while (!foundKeyframe && (sample = NextSample())) {
     if (sample->mKeyframe) {
       frameTime = sample->mTime;
       foundKeyframe = true;
     }
-    skipSamplesQueue.Push(sample);
+    int64_t sampleTimecode = sample->mTimecode;
+    skipSamplesQueue.Push(sample.forget());
     if (!startTime) {
-      startTime.emplace(sample->mTimecode);
+      startTime.emplace(sampleTimecode);
     } else if (!foundKeyframe &&
-               sample->mTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
+               sampleTimecode > startTime.ref() + MAX_LOOK_AHEAD) {
       WEBM_DEBUG("Couldn't find keyframe in a reasonable time, aborting");
       break;
     }
   }
   // We may have demuxed more than intended, so ensure that all frames are kept
   // in the right order.
-  mSamples.PushFront(skipSamplesQueue);
+  mSamples.PushFront(Move(skipSamplesQueue));
 
   if (frameTime != -1) {
     mNextKeyframeTime.emplace(media::TimeUnit::FromMicroseconds(frameTime));
     WEBM_DEBUG("Next Keyframe %f (%u queued %.02fs)",
                mNextKeyframeTime.value().ToSeconds(),
                uint32_t(mSamples.GetSize()),
                media::TimeUnit::FromMicroseconds(mSamples.Last()->mTimecode - mSamples.First()->mTimecode).ToSeconds());
   } else {
@@ -967,17 +966,17 @@ WebMTrackDemuxer::SkipToNextRandomAccess
   RefPtr<MediaRawData> sample;
 
   WEBM_DEBUG("TimeThreshold: %f", aTimeThreshold.ToSeconds());
   while (!found && (sample = NextSample())) {
     parsed++;
     if (sample->mKeyframe && sample->mTime >= aTimeThreshold.ToMicroseconds()) {
       found = true;
       mSamples.Reset();
-      mSamples.PushFront(sample);
+      mSamples.PushFront(sample.forget());
     }
   }
   SetNextKeyFrameTime();
   if (found) {
     WEBM_DEBUG("next sample: %f (parsed: %d)",
                media::TimeUnit::FromMicroseconds(sample->mTime).ToSeconds(),
                parsed);
     return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
--- a/dom/media/webm/WebMDemuxer.h
+++ b/dom/media/webm/WebMDemuxer.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #if !defined(WebMDemuxer_h_)
 #define WebMDemuxer_h_
 
 #include "nsTArray.h"
 #include "MediaDataDemuxer.h"
 #include "NesteggPacketHolder.h"
+#include "mozilla/Move.h"
 
 typedef struct nestegg nestegg;
 
 namespace mozilla {
 
 class WebMBufferedState;
 
 // Queue for holding MediaRawData samples
@@ -22,26 +23,32 @@ class MediaRawDataQueue {
   uint32_t GetSize() {
     return mQueue.size();
   }
 
   void Push(MediaRawData* aItem) {
     mQueue.push_back(aItem);
   }
 
-  void Push(const MediaRawDataQueue& aOther) {
-    mQueue.insert(mQueue.end(), aOther.mQueue.begin(), aOther.mQueue.end());
+  void Push(already_AddRefed<MediaRawData>&& aItem) {
+    mQueue.push_back(Move(aItem));
   }
 
   void PushFront(MediaRawData* aItem) {
     mQueue.push_front(aItem);
   }
 
-  void PushFront(const MediaRawDataQueue& aOther) {
-    mQueue.insert(mQueue.begin(), aOther.mQueue.begin(), aOther.mQueue.end());
+  void PushFront(already_AddRefed<MediaRawData>&& aItem) {
+    mQueue.push_front(Move(aItem));
+  }
+
+  void PushFront(MediaRawDataQueue&& aOther) {
+    while (!aOther.mQueue.empty()) {
+      Push(aOther.PopFront());
+    }
   }
 
   already_AddRefed<MediaRawData> PopFront() {
     RefPtr<MediaRawData> result = mQueue.front().forget();
     mQueue.pop_front();
     return result.forget();
   }
 
--- a/dom/webidl/XMLHttpRequest.webidl
+++ b/dom/webidl/XMLHttpRequest.webidl
@@ -49,17 +49,17 @@ dictionary MozXMLHttpRequestParameters
 };
 
 [Constructor(optional MozXMLHttpRequestParameters params),
  // There are apparently callers, specifically CoffeeScript, who do
  // things like this:
  //   c = new(window.ActiveXObject || XMLHttpRequest)("Microsoft.XMLHTTP")
  // To handle that, we need a constructor that takes a string.
  Constructor(DOMString ignored),
- Exposed=(Window,Worker)]
+ Exposed=(Window,DedicatedWorker,SharedWorker)]
 interface XMLHttpRequest : XMLHttpRequestEventTarget {
   // event handler
   attribute EventHandler onreadystatechange;
 
   // states
   const unsigned short UNSENT = 0;
   const unsigned short OPENED = 1;
   const unsigned short HEADERS_RECEIVED = 2;
--- a/dom/webidl/XMLHttpRequestEventTarget.webidl
+++ b/dom/webidl/XMLHttpRequestEventTarget.webidl
@@ -5,17 +5,17 @@
  *
  * The origin of this IDL file is
  * www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-[Exposed=(Window,Worker)]
+[Exposed=(Window,DedicatedWorker,SharedWorker)]
 interface XMLHttpRequestEventTarget : EventTarget {
   // event handlers
   [SetterThrows=Workers, GetterThrows=Workers]
   attribute EventHandler onloadstart;
 
   [SetterThrows=Workers, GetterThrows=Workers]
   attribute EventHandler onprogress;
 
--- a/dom/webidl/XMLHttpRequestUpload.webidl
+++ b/dom/webidl/XMLHttpRequestUpload.webidl
@@ -5,12 +5,12 @@
  *
  * The origin of this IDL file is
  * www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/
  *
  * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
  * liability, trademark and document use rules apply.
  */
 
-[Exposed=(Window,Worker)]
+[Exposed=(Window,DedicatedWorker,SharedWorker)]
 interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {
 
 };
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
+++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js
@@ -191,22 +191,16 @@ var interfaceNamesInGlobalScope =
     "ServiceWorkerGlobalScope",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ServiceWorkerRegistration",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextDecoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "TextEncoder",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    "XMLHttpRequest",
-// IMPORTANT: Do not change this list without review from a DOM peer!
-    "XMLHttpRequestEventTarget",
-// IMPORTANT: Do not change this list without review from a DOM peer!
-    "XMLHttpRequestUpload",
-// IMPORTANT: Do not change this list without review from a DOM peer!
     "URL",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "URLSearchParams",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WebSocket",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "WindowClient",
 // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/ipc/glue/Neutering.h
+++ b/ipc/glue/Neutering.h
@@ -52,13 +52,28 @@ public:
   DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
   ~DeneuteredWindowRegion();
 
 private:
   MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
   bool mReneuter;
 };
 
+class MOZ_RAII SuppressedNeuteringRegion
+{
+public:
+  SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
+  ~SuppressedNeuteringRegion();
+
+  static inline bool IsNeuteringSuppressed() { return sSuppressNeutering; }
+
+private:
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+  bool mReenable;
+
+  static bool sSuppressNeutering;
+};
+
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_Neutering_h
 
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -10,16 +10,17 @@
 #include "WindowsMessageLoop.h"
 #include "Neutering.h"
 #include "MessageChannel.h"
 
 #include "nsAutoPtr.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 #include "nsIXULAppInfo.h"
+#include "nsWindowsDllInterceptor.h"
 #include "WinUtils.h"
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/PaintTracker.h"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::ipc::windows;
@@ -431,16 +432,103 @@ ProcessOrDeferMessage(HWND hwnd,
     NS_ASSERTION(gDeferredMessages, "Out of memory!");
   }
 
   // Save for later. The array takes ownership of |deferred|.
   gDeferredMessages->AppendElement(deferred);
   return res;
 }
 
+/*
+ * It is bad to subclass a window when neutering is active because you'll end
+ * up subclassing the *neutered* window procedure instead of the real window
+ * procedure. Since CreateWindow* fires WM_CREATE (and could thus trigger
+ * neutering), we intercept these calls and suppress neutering for the duration
+ * of the call. This ensures that any subsequent subclassing replaces the
+ * correct window procedure.
+ */
+WindowsDllInterceptor sUser32Interceptor;
+typedef HWND (WINAPI *CreateWindowExWPtr)(DWORD,LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+typedef HWND (WINAPI *CreateWindowExAPtr)(DWORD,LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+typedef HWND (WINAPI *CreateWindowWPtr)(LPCWSTR,LPCWSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+typedef HWND (WINAPI *CreateWindowAPtr)(LPCSTR,LPCSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
+
+CreateWindowExWPtr sCreateWindowExWStub = nullptr;
+CreateWindowExAPtr sCreateWindowExAStub = nullptr;
+CreateWindowWPtr sCreateWindowWStub = nullptr;
+CreateWindowAPtr sCreateWindowAStub = nullptr;
+
+HWND WINAPI
+CreateWindowExWHook(DWORD aExStyle, LPCWSTR aClassName, LPCWSTR aWindowName,
+                    DWORD aStyle, int aX, int aY, int aWidth, int aHeight,
+                    HWND aParent, HMENU aMenu, HINSTANCE aInstance,
+                    LPVOID aParam)
+{
+  SuppressedNeuteringRegion doNotNeuterThisWindowYet;
+  return sCreateWindowExWStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY,
+                              aWidth, aHeight, aParent, aMenu, aInstance, aParam);
+}
+
+HWND WINAPI
+CreateWindowExAHook(DWORD aExStyle, LPCSTR aClassName, LPCSTR aWindowName,
+                    DWORD aStyle, int aX, int aY, int aWidth, int aHeight,
+                    HWND aParent, HMENU aMenu, HINSTANCE aInstance,
+                    LPVOID aParam)
+{
+  SuppressedNeuteringRegion doNotNeuterThisWindowYet;
+  return sCreateWindowExAStub(aExStyle, aClassName, aWindowName, aStyle, aX, aY,
+                              aWidth, aHeight, aParent, aMenu, aInstance, aParam);
+}
+
+HWND WINAPI
+CreateWindowWHook(LPCWSTR aClassName, LPCWSTR aWindowName, DWORD aStyle, int aX,
+                  int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu,
+                  HINSTANCE aInstance, LPVOID aParam)
+{
+  SuppressedNeuteringRegion doNotNeuterThisWindowYet;
+  return sCreateWindowWStub(aClassName, aWindowName, aStyle, aX, aY, aWidth,
+                            aHeight, aParent, aMenu, aInstance, aParam);
+}
+
+HWND WINAPI
+CreateWindowAHook(LPCSTR aClassName, LPCSTR aWindowName, DWORD aStyle, int aX,
+                  int aY, int aWidth, int aHeight, HWND aParent, HMENU aMenu,
+                  HINSTANCE aInstance, LPVOID aParam)
+{
+  SuppressedNeuteringRegion doNotNeuterThisWindowYet;
+  return sCreateWindowAStub(aClassName, aWindowName, aStyle, aX, aY, aWidth,
+                            aHeight, aParent, aMenu, aInstance, aParam);
+}
+
+void
+InitCreateWindowHook()
+{
+  sUser32Interceptor.Init("user32.dll");
+  if (!sCreateWindowExWStub) {
+    sUser32Interceptor.AddHook("CreateWindowExW",
+                               reinterpret_cast<intptr_t>(CreateWindowExWHook),
+                               (void**) &sCreateWindowExWStub);
+  }
+  if (!sCreateWindowExAStub) {
+    sUser32Interceptor.AddHook("CreateWindowExA",
+                               reinterpret_cast<intptr_t>(CreateWindowExAHook),
+                               (void**) &sCreateWindowExAStub);
+  }
+  if (!sCreateWindowWStub) {
+    sUser32Interceptor.AddHook("CreateWindowW",
+                               reinterpret_cast<intptr_t>(CreateWindowWHook),
+                               (void**) &sCreateWindowWStub);
+  }
+  if (!sCreateWindowAStub) {
+    sUser32Interceptor.AddHook("CreateWindowA",
+                               reinterpret_cast<intptr_t>(CreateWindowAHook),
+                               (void**) &sCreateWindowAStub);
+  }
+}
+
 } // namespace
 
 // We need the pointer value of this in PluginInstanceChild.
 LRESULT CALLBACK
 NeuteredWindowProc(HWND hwnd,
                    UINT uMsg,
                    WPARAM wParam,
                    LPARAM lParam)
@@ -605,17 +693,19 @@ CallWindowProcedureHook(int nCode,
                         WPARAM wParam,
                         LPARAM lParam)
 {
   if (nCode >= 0) {
     NS_ASSERTION(gNeuteredWindows, "This should never be null!");
 
     HWND hWnd = reinterpret_cast<CWPSTRUCT*>(lParam)->hwnd;
 
-    if (!gNeuteredWindows->Contains(hWnd) && NeuterWindowProcedure(hWnd)) {
+    if (!gNeuteredWindows->Contains(hWnd) &&
+        !SuppressedNeuteringRegion::IsNeuteringSuppressed() &&
+        NeuterWindowProcedure(hWnd)) {
       if (!gNeuteredWindows->AppendElement(hWnd)) {
         NS_ERROR("Out of memory!");
         RestoreWindowProcedure(hWnd);
       }
     }
   }
   return CallNextHookEx(nullptr, nCode, wParam, lParam);
 }
@@ -705,16 +795,18 @@ InitUIThread()
                                     NULL, &WinEventHook, GetCurrentProcessId(),
                                     gUIThreadId, WINEVENT_OUTOFCONTEXT);
 
     // We need to execute this after setting the hook in case the OLE window
     // already existed.
     gCOMWindow = FindCOMWindow();
   }
   MOZ_ASSERT(gWinEventHook);
+
+  InitCreateWindowHook();
 }
 
 } // namespace windows
 } // namespace ipc
 } // namespace mozilla
 
 // See SpinInternalEventLoop below
 MessageChannel::SyncStackFrame::SyncStackFrame(MessageChannel* channel, bool interrupt)
@@ -938,16 +1030,36 @@ DeneuteredWindowRegion::DeneuteredWindow
 
 DeneuteredWindowRegion::~DeneuteredWindowRegion()
 {
   if (mReneuter) {
     StartNeutering();
   }
 }
 
+SuppressedNeuteringRegion::SuppressedNeuteringRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
+  : mReenable(::gUIThreadId == ::GetCurrentThreadId() && ::gWindowHook)
+{
+  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+  if (mReenable) {
+    MOZ_ASSERT(!sSuppressNeutering);
+    sSuppressNeutering = true;
+  }
+}
+
+SuppressedNeuteringRegion::~SuppressedNeuteringRegion()
+{
+  if (mReenable) {
+    MOZ_ASSERT(sSuppressNeutering);
+    sSuppressNeutering = false;
+  }
+}
+
+bool SuppressedNeuteringRegion::sSuppressNeutering = false;
+
 bool
 MessageChannel::WaitForSyncNotify(bool aHandleWindowsMessages)
 {
   mMonitor->AssertCurrentThreadOwns();
 
   MOZ_ASSERT(gUIThreadId, "InitUIThread was not called!");
 
   // Use a blocking wait if this channel does not require
@@ -992,16 +1104,18 @@ MessageChannel::WaitForSyncNotify(bool a
     InitTimeoutData(&timeoutData, mTimeoutMs);
 
     // We only do this to ensure that we won't get stuck in
     // MsgWaitForMultipleObjects below.
     timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr);
     NS_ASSERTION(timerId, "SetTimer failed!");
   }
 
+  NeuteredWindowRegion neuteredRgn(true);
+
   {
     while (1) {
       MSG msg = { 0 };
       // Don't get wrapped up in here if the child connection dies.
       {
         MonitorAutoLock lock(*mMonitor);
         if (!Connected()) {
           break;
--- a/js/src/asmjs/AsmJSCompile.cpp
+++ b/js/src/asmjs/AsmJSCompile.cpp
@@ -118,16 +118,21 @@ class ModuleCompiler
     bool getOrCreateFunctionEntry(uint32_t funcIndex, Label** label)
     {
         return compileResults_->getOrCreateFunctionEntry(funcIndex, label);
     }
 
     bool finishGeneratingFunction(AsmFunction& func, CodeGenerator& codegen,
                                   const AsmJSFunctionLabels& labels)
     {
+        // If we have hit OOM then invariants which we assert below may not
+        // hold, so abort now.
+        if (masm().oom())
+            return false;
+
         // Code range
         unsigned line = func.lineno();
         unsigned column = func.column();
         PropertyName* funcName = func.name();
         if (!compileResults_->addCodeRange(AsmJSModule::FunctionCodeRange(funcName, line, labels)))
             return false;
 
         // Script counts
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -636,21 +636,18 @@ ArrayMetaTypeDescr::create(JSContext* cx
     return obj;
 }
 
 bool
 ArrayMetaTypeDescr::construct(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!args.isConstructing()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                             JSMSG_NOT_FUNCTION, "ArrayType");
+    if (!ThrowIfNotConstructing(cx, args, "ArrayType"))
         return false;
-    }
 
     RootedObject arrayTypeGlobal(cx, &args.callee());
 
     // Expect two arguments. The first is a type object, the second is a length.
     if (args.length() < 2) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "ArrayType", "1", "");
         return false;
@@ -993,21 +990,18 @@ StructMetaTypeDescr::create(JSContext* c
     return descr;
 }
 
 bool
 StructMetaTypeDescr::construct(JSContext* cx, unsigned int argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!args.isConstructing()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
-                             JSMSG_NOT_FUNCTION, "StructType");
+    if (!ThrowIfNotConstructing(cx, args, "StructType"))
         return false;
-    }
 
     if (args.length() >= 1 && args[0].isObject()) {
         RootedObject metaTypeDescr(cx, &args.callee());
         RootedObject fields(cx, &args[0].toObject());
         RootedObject obj(cx, create(cx, metaTypeDescr, fields));
         if (!obj)
             return false;
         args.rval().setObject(*obj);
--- a/js/src/builtin/WeakSetObject.cpp
+++ b/js/src/builtin/WeakSetObject.cpp
@@ -80,20 +80,18 @@ WeakSetObject::construct(JSContext* cx, 
 {
     Rooted<WeakSetObject*> obj(cx, WeakSetObject::create(cx));
     if (!obj)
         return false;
 
     // Based on our "Set" implementation instead of the more general ES6 steps.
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!args.isConstructing()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, "WeakSet");
+    if (!ThrowIfNotConstructing(cx, args, "WeakSet"))
         return false;
-    }
 
     if (!args.get(0).isNullOrUndefined()) {
         RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
 
         RootedValue adderVal(cx);
         if (!GetProperty(cx, obj, obj, cx->names().add, &adderVal))
             return false;
 
--- a/js/src/jit-test/lib/bytecode-cache.js
+++ b/js/src/jit-test/lib/bytecode-cache.js
@@ -4,17 +4,17 @@ function evalWithCache(code, ctx) {
   ctx = Object.create(ctx, {
     fileName: { value: "evalWithCacheCode.js" },
     lineNumber: { value: 0 }
   });
   code = code instanceof Object ? code : cacheEntry(code);
 
   // We create a new global ...
   if (!("global" in ctx))
-    ctx.global = newGlobal();
+    ctx.global = newGlobal({ cloneSingletons: true });
 
   if (!("isRunOnce" in ctx))
     ctx.isRunOnce = true;
 
   // Fetch the verification function from the evaluation context.  This function
   // is used to assert the state of the script/function after each run of the
   // evaluate function.
   var checkAfter = ctx.checkAfter || function(ctx) {};
--- a/js/src/jit-test/tests/basic/bug1057571.js
+++ b/js/src/jit-test/tests/basic/bug1057571.js
@@ -3,12 +3,13 @@ test = (function () {
   function f() {
     [1,2,3,4,5];
   };
   return "var obj = { x : 2 };" + f.toSource() + "; f()";
 })();
 evalWithCache(test, {});
 function evalWithCache(code, ctx) {
   code = cacheEntry(code);
+  ctx.global = newGlobal({ cloneSingletons: true });
   ctx.isRunOnce = true;
   var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
   var res2 = evaluate(code, Object.create(ctx, {loadBytecode: { value: true }, saveBytecode: { value: true } }));
 }
--- a/js/src/jit-test/tests/basic/bug1061534.js
+++ b/js/src/jit-test/tests/basic/bug1061534.js
@@ -1,14 +1,15 @@
 
 test = (function () {
   function f() {};
   return "var obj = { x : 2 };" + f.toSource() + (4);
 })();
 evalWithCache(test, {});
 function evalWithCache(code, ctx) {
   code = cacheEntry(code);
+  ctx.global = newGlobal({ cloneSingletons: true });
   var res1 = evaluate(code, Object.create(ctx, {saveBytecode: { value: true } }));
 }
 if (typeof assertThrowsInstanceOf === 'undefined') {
     var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) {};
 }
 evaluate('evaluate(\'assertThrowsInstanceOf(function () {}, ["jak", "ms"]);\', { noScriptRval : true, isRunOnce: true  })');
--- a/js/src/jit-test/tests/gc/bug-1108007.js
+++ b/js/src/jit-test/tests/gc/bug-1108007.js
@@ -1,16 +1,16 @@
 // |jit-test| --no-threads; --no-ion; --no-baseline
 if (!("gczeal" in this))
     quit();
 gczeal(2);
 (function() {
     evaluate(cacheEntry((function() {
         return "".toSource()
-    })()), Object.create({}, {
+    })()), Object.create({ global: newGlobal({ cloneSingletons: true }) }, {
         saveBytecode: {
             value: true
         }
     }))
 })();
 [[0], [0], [0], [0], [0], [0], [0], [0], [0], [0],
  [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], 
  [0], [0], [0], [0], [0], [0], [0], [0], [0], [0], 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/xdr/bug1108603.js
@@ -0,0 +1,9 @@
+var caught = false;
+try {
+  evaluate(cacheEntry(""), {saveBytecode: {value: true}, global: this});
+  [[0]];
+} catch (err) {
+  caught = true;
+  assertEq(err.message, "compartment cannot save singleton anymore.");
+}
+assertEq(caught, true);
\ No newline at end of file
--- a/js/src/jit-test/tests/xdr/lazy.js
+++ b/js/src/jit-test/tests/xdr/lazy.js
@@ -145,17 +145,17 @@ test = `
   function f() { return true; };
   var canBeLazy = isRelazifiableFunction(f) || isLazyFunction(f);
   relazifyFunctions();
   assertEq(isLazyFunction(f), canBeLazy);
   f()`
 evalWithCache(test, { assertEqBytecode: true, assertEqResult: true });
 
 // And more of the same, in a slightly different way
-var g1 = newGlobal();
+var g1 = newGlobal({ cloneSingletons: true });
 var g2 = newGlobal();
 var res = "function f(){}";
 var code = cacheEntry(res + "; f();");
 evaluate(code, {global:g1, compileAndGo: true, saveBytecode: {value: true}});
 evaluate(code, {global:g2, loadBytecode: true});
 gc();
 assertEq(g2.f.toString(), res);
 
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -2174,17 +2174,17 @@ Assembler::as_BranchPool(uint32_t value,
     php.phd.init(0, c, PoolHintData::PoolBranch, pc);
     BufferOffset ret = allocEntry(1, 1, (uint8_t*)&php.raw, (uint8_t*)&value, pe,
                                   /* markAsBranch = */ true, /* loadToPC = */ true);
     // If this label is already bound, then immediately replace the stub load
     // with a correct branch.
     if (label->bound()) {
         BufferOffset dest(label);
         as_b(dest.diffB<BOffImm>(ret), c, ret);
-    } else {
+    } else if (!oom()) {
         label->use(ret.getOffset());
     }
 #ifdef JS_DISASM_ARM
     if (documentation)
         spewTarget(documentation);
 #endif
     return ret;
 }
@@ -2374,47 +2374,52 @@ Assembler::as_b(BOffImm off, Condition c
 {
     BufferOffset ret = writeBranchInst(((int)c) | OpB | off.encode(), documentation);
     return ret;
 }
 
 BufferOffset
 Assembler::as_b(Label* l, Condition c)
 {
-    if (m_buffer.oom()) {
-        BufferOffset ret;
-        return ret;
-    }
-
     if (l->bound()) {
         // Note only one instruction is emitted here, the NOP is overwritten.
         BufferOffset ret = allocBranchInst();
+        if (oom())
+            return BufferOffset();
+
         as_b(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
 #ifdef JS_DISASM_ARM
         spewBranch(m_buffer.getInstOrNull(ret), l);
 #endif
         return ret;
     }
 
+    if (oom())
+        return BufferOffset();
+
     int32_t old;
     BufferOffset ret;
     if (l->used()) {
         old = l->offset();
         // This will currently throw an assertion if we couldn't actually
         // encode the offset of the branch.
         if (!BOffImm::IsInRange(old)) {
             m_buffer.fail_bail();
             return ret;
         }
         ret = as_b(BOffImm(old), c, l);
     } else {
         old = LabelBase::INVALID_OFFSET;
         BOffImm inv;
         ret = as_b(inv, c, l);
     }
+
+    if (oom())
+        return BufferOffset();
+
     DebugOnly<int32_t> check = l->use(ret.getOffset());
     MOZ_ASSERT(check == old);
     return ret;
 }
 
 BufferOffset
 Assembler::as_b(BOffImm off, Condition c, BufferOffset inst)
 {
@@ -2441,31 +2446,32 @@ BufferOffset
 Assembler::as_bl(BOffImm off, Condition c, Label* documentation)
 {
     return writeBranchInst(((int)c) | OpBl | off.encode(), documentation);
 }
 
 BufferOffset
 Assembler::as_bl(Label* l, Condition c)
 {
-    if (m_buffer.oom()) {
-        BufferOffset ret;
-        return ret;
-    }
-
     if (l->bound()) {
         // Note only one instruction is emitted here, the NOP is overwritten.
         BufferOffset ret = allocBranchInst();
+        if (oom())
+            return BufferOffset();
+
         as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
 #ifdef JS_DISASM_ARM
         spewBranch(m_buffer.getInstOrNull(ret), l);
 #endif
         return ret;
     }
 
+    if (oom())
+        return BufferOffset();
+
     int32_t old;
     BufferOffset ret;
     // See if the list was empty :(
     if (l->used()) {
         // This will currently throw an assertion if we couldn't actually encode
         // the offset of the branch.
         old = l->offset();
         if (!BOffImm::IsInRange(old)) {
@@ -2473,16 +2479,20 @@ Assembler::as_bl(Label* l, Condition c)
             return ret;
         }
         ret = as_bl(BOffImm(old), c, l);
     } else {
         old = LabelBase::INVALID_OFFSET;
         BOffImm inv;
         ret = as_bl(inv, c, l);
     }
+
+    if (oom())
+        return BufferOffset();
+
     DebugOnly<int32_t> check = l->use(ret.getOffset());
     MOZ_ASSERT(check == old);
     return ret;
 }
 
 BufferOffset
 Assembler::as_bl(BOffImm off, Condition c, BufferOffset inst)
 {
--- a/js/src/jit/shared/IonAssemblerBuffer.h
+++ b/js/src/jit/shared/IonAssemblerBuffer.h
@@ -147,18 +147,23 @@ class AssemblerBuffer
             fail_oom();
             return nullptr;
         }
         return new (tmp) Slice;
     }
 
     bool ensureSpace(int size) {
         // Space can exist in the most recent Slice.
-        if (tail && tail->length() + size <= tail->Capacity())
+        if (tail && tail->length() + size <= tail->Capacity()) {
+            // Simulate allocation failure even when we don't need a new slice.
+            if (js::oom::ShouldFailWithOOM())
+                return fail_oom();
+
             return true;
+        }
 
         // Otherwise, a new Slice must be added.
         Slice* slice = newSlice(lifoAlloc_);
         if (slice == nullptr)
             return fail_oom();
 
         // If this is the first Slice in the buffer, add to head position.
         if (!head) {
--- a/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
+++ b/js/src/jit/shared/IonAssemblerBufferWithConstantPools.h
@@ -699,16 +699,18 @@ struct AssemblerBufferWithConstantPools 
         // Should not be placing a pool in a no-pool region, check.
         MOZ_ASSERT(!canNotPlacePool_);
 
         // Dump the pool with a guard branch around the pool.
         BufferOffset branch = this->nextOffset();
         // Mark and emit the guard branch.
         markNextAsBranch();
         this->putBytes(guardSize_ * InstSize, nullptr);
+        if (this->oom())
+            return;
         BufferOffset afterPool = this->nextOffset();
         Asm::WritePoolGuard(branch, this->getInst(branch), afterPool);
 
         // Perforate the buffer which finishes the current slice and allocates a
         // new slice. This is necessary because Pools are always placed after
         // the end of a slice.
         BufferSlice* perforatedSlice = getTail();
         BufferOffset perforation = this->nextOffset();
@@ -859,17 +861,17 @@ struct AssemblerBufferWithConstantPools 
         if (pool_.checkFull(poolOffset)) {
             // Alignment would cause a pool dump, so dump the pool now.
             JitSpew(JitSpew_Pools, "[%d] Alignment of %d at %d caused a spill.", id, alignment,
                     sizeExcludingCurrentPool());
             finishPool();
         }
 
         inhibitNops_ = true;
-        while (sizeExcludingCurrentPool() & (alignment - 1))
+        while ((sizeExcludingCurrentPool() & (alignment - 1)) && !this->oom())
             putInt(alignFillInst_);
         inhibitNops_ = false;
     }
 
   private:
     void patchBranch(Inst* i, unsigned curpool, BufferOffset branch) {
         const Inst* ci = i;
         ptrdiff_t offset = Asm::GetBranchOffset(ci);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -72,18 +72,17 @@ MSG_DEF(JSMSG_INVALID_MAP_ITERABLE,    1
 MSG_DEF(JSMSG_NESTING_GENERATOR,       0, JSEXN_TYPEERR, "already executing generator")
 MSG_DEF(JSMSG_INCOMPATIBLE_METHOD,     3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}")
 MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead")
 MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS,       0, JSEXN_TYPEERR, "invalid arguments")
 MSG_DEF(JSMSG_BAD_SURROGATE_CHAR,      1, JSEXN_TYPEERR, "bad surrogate character {0}")
 MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE,     1, JSEXN_TYPEERR, "UTF-8 character {0} too large")
 MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR,     1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}")
 MSG_DEF(JSMSG_WRONG_CONSTRUCTOR,       1, JSEXN_TYPEERR, "wrong constructor called for {0}")
-MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW,     1, JSEXN_NONE, "calling a builtin {0} constructor without new is deprecated and will be forbidden in ES6")
-MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW_FATAL, 1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
+MSG_DEF(JSMSG_BUILTIN_CTOR_NO_NEW,     1, JSEXN_TYPEERR, "calling a builtin {0} constructor without new is forbidden")
 MSG_DEF(JSMSG_PROTO_SETTING_SLOW,      0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
 MSG_DEF(JSMSG_BAD_GENERATOR_YIELD,     1, JSEXN_TYPEERR, "yield from closing generator {0}")
 MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE,      0, JSEXN_TYPEERR, "reduce of empty array with no initial value")
 MSG_DEF(JSMSG_UNEXPECTED_TYPE,         2, JSEXN_TYPEERR, "{0} is {1}")
 MSG_DEF(JSMSG_MISSING_FUN_ARG,         2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}")
 MSG_DEF(JSMSG_NOT_NONNULL_OBJECT,      1, JSEXN_TYPEERR, "{0} is not a non-null object")
 MSG_DEF(JSMSG_SET_NON_OBJECT_RECEIVER, 1, JSEXN_TYPEERR, "can't assign to properties of {0}: not an object")
 MSG_DEF(JSMSG_INVALID_DESCRIPTOR,      0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified")
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -1237,20 +1237,18 @@ NewScriptedProxy(JSContext* cx, CallArgs
     return true;
 }
 
 bool
 js::proxy(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!args.isConstructing()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_FUNCTION, "Proxy");
+    if (!ThrowIfNotConstructing(cx, args, "Proxy"))
         return false;
-    }
 
     return NewScriptedProxy(cx, args, "Proxy");
 }
 
 static bool
 RevokeProxy(JSContext* cx, unsigned argc, Value* vp)
 {
     CallReceiver rec = CallReceiverFromVp(vp);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1240,22 +1240,24 @@ Evaluate(JSContext* cx, unsigned argc, V
         if (saveFrameChain && !asfc.save())
             return false;
 
         JSAutoCompartment ac(cx, global);
         RootedScript script(cx);
 
         {
             if (saveBytecode) {
-                if (!JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()) {
+                if (!JS::CompartmentOptionsRef(cx).cloneSingletons()) {
                     JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                          JSSMSG_CACHE_SINGLETON_FAILED);
                     return false;
                 }
-                JS::CompartmentOptionsRef(cx).setCloneSingletons(true);
+
+                // cloneSingletons implies that singletons are used as template objects.
+                MOZ_ASSERT(JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates());
             }
 
             if (loadBytecode) {
                 script = JS_DecodeScript(cx, loadBuffer, loadLength);
             } else {
                 mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
                 (void) JS::Compile(cx, options, chars.start().get(), chars.length(), &script);
             }
@@ -3800,16 +3802,21 @@ NewGlobal(JSContext* cx, unsigned argc, 
         if (v.isObject())
             options.setSameZoneAs(UncheckedUnwrap(&v.toObject()));
 
         if (!JS_GetProperty(cx, opts, "invisibleToDebugger", &v))
             return false;
         if (v.isBoolean())
             options.setInvisibleToDebugger(v.toBoolean());
 
+        if (!JS_GetProperty(cx, opts, "cloneSingletons", &v))
+            return false;
+        if (v.isBoolean())
+            options.setCloneSingletons(v.toBoolean());
+
         if (!JS_GetProperty(cx, opts, "principal", &v))
             return false;
         if (!v.isUndefined()) {
             uint32_t bits;
             if (!ToUint32(cx, v, &bits))
                 return false;
             principals = cx->new_<ShellPrincipals>(bits);
             if (!principals)
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -584,14 +584,14 @@ LookupPropertyInline(ExclusiveContext* c
 }
 
 inline bool
 ThrowIfNotConstructing(JSContext *cx, const CallArgs &args, const char *builtinName)
 {
     if (args.isConstructing())
         return true;
     return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, GetErrorMessage, nullptr,
-                                        JSMSG_BUILTIN_CTOR_NO_NEW_FATAL, builtinName);
+                                        JSMSG_BUILTIN_CTOR_NO_NEW, builtinName);
 }
 
 } // namespace js
 
 #endif /* vm_NativeObject_inl_h */
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -24,21 +24,21 @@ namespace js {
  * versions.  If deserialization fails, the data should be invalidated if
  * possible.
  *
  * When you change this, run make_opcode_doc.py and copy the new output into
  * this wiki page:
  *
  *  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
  */
-static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 313;
+static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 314;
 static const uint32_t XDR_BYTECODE_VERSION =
     uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
 
-static_assert(JSErr_Limit == 419,
+static_assert(JSErr_Limit == 418,
               "GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
               "removed MSG_DEFs from js.msg, you should increment "
               "XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "
               "expected JSErr_Limit value.");
 
 class XDRBuffer {
   public:
     explicit XDRBuffer(JSContext* cx)
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1249,16 +1249,18 @@ XRE_XPCShellMain(int argc, char** argv, 
     nsresult rv;
 
     gErrFile = stderr;
     gOutFile = stdout;
     gInFile = stdin;
 
     NS_LogInit();
 
+    mozilla::LogModule::Init();
+
     // A initializer to initialize histogram collection
     // used by telemetry.
     UniquePtr<base::StatisticsRecorder> telStats =
        MakeUnique<base::StatisticsRecorder>();
 
     if (PR_GetEnv("MOZ_CHAOSMODE")) {
         ChaosFeature feature = ChaosFeature::Any;
         long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
--- a/layout/forms/nsFileControlFrame.cpp
+++ b/layout/forms/nsFileControlFrame.cpp
@@ -122,19 +122,24 @@ MakeAnonButton(nsIDocument* aDoc, const 
   return button.forget();
 }
 
 nsresult
 nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
 {
   nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
 
+#if defined(ANDROID) || defined(MOZ_B2G)
+   bool isDirPicker = false;
+#else
   nsIContent* content = GetContent();
-  bool isDirPicker = Preferences::GetBool("dom.input.dirpicker", false) &&
-                     content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::directory);
+  bool isDirPicker =
+    Preferences::GetBool("dom.input.dirpicker", false) &&
+    content && content->HasAttr(kNameSpaceID_None, nsGkAtoms::directory);
+#endif
 
   RefPtr<HTMLInputElement> fileContent = HTMLInputElement::FromContentOrNull(mContent);
 
   // The access key is transferred to the "Choose files..." button only. In
   // effect that access key allows access to the control via that button, then
   // the user can tab between the two buttons.
   nsAutoString accessKey;
   fileContent->GetAccessKey(accessKey);
--- a/media/webrtc/signaling/signaling.gyp
+++ b/media/webrtc/signaling/signaling.gyp
@@ -67,17 +67,16 @@
         './src/common',
         './src/common/browser_logging',
         './src/common/time_profiling',
         './src/media',
         './src/media-conduit',
         './src/mediapipeline',
         './src/peerconnection',
         './src/sdp/sipcc',
-        '../../../xpcom/base',
         '../../../dom/base',
         '../../../dom/media',
         '../../../media/mtransport',
         '../trunk',
         '../../libyuv/include',
         '../../mtransport/third_party/nrappkit/src/util/libekr',
       ],
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.cpp
@@ -18,17 +18,17 @@
 #include <mozilla/Types.h>
 #endif
 
 #include "nsNetCID.h" // NS_SOCKETTRANSPORTSERVICE_CONTRACTID
 #include "nsServiceManagerUtils.h" // do_GetService
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "mozilla/Services.h"
-#include "StaticPtr.h"
+#include "mozilla/StaticPtr.h"
 
 #include "gmp-video-decode.h" // GMP_API_VIDEO_DECODER
 #include "gmp-video-encode.h" // GMP_API_VIDEO_ENCODER
 
 static const char* logTag = "PeerConnectionCtx";
 
 namespace mozilla {
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionCtx.h
@@ -7,17 +7,17 @@
 
 #include <string>
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
 #include "WebrtcGlobalChild.h"
 #endif
 
 #include "mozilla/Attributes.h"
-#include "StaticPtr.h"
+#include "mozilla/StaticPtr.h"
 #include "PeerConnectionImpl.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "nsIRunnable.h"
 
 namespace mozilla {
 class PeerConnectionCtxShutdown;
 
 namespace dom {
new file mode 100644
--- /dev/null
+++ b/netwerk/base/ARefBase.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; 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/. */
+
+#ifndef mozilla_net_ARefBase_h
+#define mozilla_net_ARefBase_h
+
+namespace mozilla { namespace net {
+
+// This is an abstract class that can be pointed to by either
+// nsCOMPtr or nsRefPtr. nsHttpConnectionMgr uses it for generic
+// objects that need to be reference counted - similiar to nsISupports
+// but it may or may not be xpcom.
+
+class ARefBase
+{
+public:
+  ARefBase() {}
+  virtual ~ARefBase() {}
+
+  NS_IMETHOD_ (MozExternalRefCountType) AddRef() = 0;
+  NS_IMETHOD_ (MozExternalRefCountType) Release() = 0;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif
--- a/netwerk/base/EventTokenBucket.cpp
+++ b/netwerk/base/EventTokenBucket.cpp
@@ -85,17 +85,16 @@ EventTokenBucket::EventTokenBucket(uint3
   , mPaused(false)
   , mStopped(false)
   , mTimerArmed(false)
 #ifdef XP_WIN
   , mFineGrainTimerInUse(false)
   , mFineGrainResetTimerArmed(false)
 #endif
 {
-  MOZ_COUNT_CTOR(EventTokenBucket);
   mLastUpdate = TimeStamp::Now();
 
   MOZ_ASSERT(NS_IsMainThread());
 
   nsresult rv;
   nsCOMPtr<nsIEventTarget> sts;
   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
   if (NS_SUCCEEDED(rv))
@@ -107,17 +106,16 @@ EventTokenBucket::EventTokenBucket(uint3
   SetRate(eventsPerSecond, burstSize);
 }
 
 EventTokenBucket::~EventTokenBucket()
 {
   SOCKET_LOG(("EventTokenBucket::dtor %p events=%d\n",
               this, mEvents.GetSize()));
 
-  MOZ_COUNT_DTOR(EventTokenBucket);
   if (mTimer && mTimerArmed)
     mTimer->Cancel();
 
 #ifdef XP_WIN
   NormalTimers();
   if (mFineGrainResetTimerArmed) {
     mFineGrainResetTimerArmed = false;
     mFineGrainResetTimer->Cancel();
--- a/netwerk/base/EventTokenBucket.h
+++ b/netwerk/base/EventTokenBucket.h
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 NetEventTokenBucket_h__
 #define NetEventTokenBucket_h__
 
+#include "ARefBase.h"
 #include "nsCOMPtr.h"
 #include "nsDeque.h"
 #include "nsITimer.h"
 
 #include "mozilla/TimeStamp.h"
 
 class nsICancelable;
 
@@ -54,28 +55,26 @@ namespace net {
   + An event is submitted to the token bucket asynchronously through SubmitEvent().
     The OnTokenBucketAdmitted() method of the submitted event is used as a callback
     when the event is ready to run. A cancelable event is returned to the SubmitEvent() caller
     for use in the case they do not wish to wait for the callback.
 */
 
 class EventTokenBucket;
 
-class ATokenBucketEvent 
+class ATokenBucketEvent
 {
 public:
   virtual void OnTokenBucketAdmitted() = 0;
 };
 
 class TokenBucketCancelable;
 
-class EventTokenBucket : public nsITimerCallback
+class EventTokenBucket : public nsITimerCallback, public ARefBase
 {
-  virtual ~EventTokenBucket();
-
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
   // This should be constructed on the main thread
   EventTokenBucket(uint32_t eventsPerSecond, uint32_t burstSize);
 
   // These public methods are all meant to be called from the socket thread
@@ -88,16 +87,18 @@ public:
   void Pause();
   void UnPause();
   void Stop() { mStopped = true; }
 
   // The returned cancelable event can only be canceled from the socket thread
   nsresult SubmitEvent(ATokenBucketEvent *event, nsICancelable **cancelable);
 
 private:
+  virtual ~EventTokenBucket();
+
   friend class RunNotifyEvent;
   friend class SetTimerEvent;
 
   bool TryImmediateDispatch(TokenBucketCancelable *event);
   void SetRate(uint32_t eventsPerSecond, uint32_t burstSize);
 
   void DispatchEvents();
   void UpdateTimer();
--- a/netwerk/protocol/http/ConnectionDiagnostics.cpp
+++ b/netwerk/protocol/http/ConnectionDiagnostics.cpp
@@ -23,17 +23,17 @@ namespace net {
 
 void
 nsHttpConnectionMgr::PrintDiagnostics()
 {
   PostEvent(&nsHttpConnectionMgr::OnMsgPrintDiagnostics, 0, nullptr);
 }
 
 void
-nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, void *)
+nsHttpConnectionMgr::OnMsgPrintDiagnostics(int32_t, ARefBase *)
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
   nsCOMPtr<nsIConsoleService> consoleService =
     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
   if (!consoleService)
     return;
 
--- a/netwerk/protocol/http/nsHttpConnection.h
+++ b/netwerk/protocol/http/nsHttpConnection.h
@@ -9,16 +9,17 @@
 #include "nsHttpConnectionInfo.h"
 #include "nsAHttpTransaction.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsProxyRelease.h"
 #include "prinrval.h"
 #include "TunnelUtils.h"
 #include "mozilla/Mutex.h"
+#include "ARefBase.h"
 
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsITimer.h"
 
 class nsISocketTransport;
 class nsISSLSocketControl;
@@ -38,16 +39,17 @@ class ASpdySession;
 
 class nsHttpConnection final : public nsAHttpSegmentReader
                              , public nsAHttpSegmentWriter
                              , public nsIInputStreamCallback
                              , public nsIOutputStreamCallback
                              , public nsITransportEventSink
                              , public nsIInterfaceRequestor
                              , public NudgeTunnelCallback
+                             , public ARefBase
 {
     virtual ~nsHttpConnection();
 
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSAHTTPSEGMENTREADER
     NS_DECL_NSAHTTPSEGMENTWRITER
     NS_DECL_NSIINPUTSTREAMCALLBACK
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -7,16 +7,17 @@
 #ifndef nsHttpConnectionInfo_h__
 #define nsHttpConnectionInfo_h__
 
 #include "nsHttp.h"
 #include "nsProxyInfo.h"
 #include "nsCOMPtr.h"
 #include "nsStringFwd.h"
 #include "mozilla/Logging.h"
+#include "ARefBase.h"
 
 extern PRLogModuleInfo *gHttpLog;
 
 //-----------------------------------------------------------------------------
 // nsHttpConnectionInfo - holds the properties of a connection
 //-----------------------------------------------------------------------------
 
 // http:// uris through a proxy will all share the same CI, because they can
@@ -25,17 +26,17 @@ extern PRLogModuleInfo *gHttpLog;
 // however, https:// uris tunnel through the proxy so they will have different
 // CIs - the CI reflects both the proxy and the origin.
 // however, proxy conenctions made with http/2 (or spdy) can tunnel to the origin
 // and multiplex non tunneled transactions at the same time, so they have a
 // special wildcard CI that accepts all origins through that proxy.
 
 namespace mozilla { namespace net {
 
-class nsHttpConnectionInfo
+class nsHttpConnectionInfo: public ARefBase
 {
 public:
     nsHttpConnectionInfo(const nsACString &originHost,
                          int32_t originPort,
                          const nsACString &npnToken,
                          const nsACString &username,
                          nsProxyInfo *proxyInfo,
                          bool endToEndSSL = false);
@@ -157,16 +158,16 @@ private:
     nsCString              mUsername;
     nsCOMPtr<nsProxyInfo>  mProxyInfo;
     bool                   mUsingHttpProxy;
     bool                   mUsingHttpsProxy;
     bool                   mEndToEndSSL;
     bool                   mUsingConnect;  // if will use CONNECT with http proxy
     nsCString              mNPNToken;
 
-// for nsRefPtr
+// for RefPtr
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo)
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // nsHttpConnectionInfo_h__
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -142,65 +142,105 @@ nsHttpConnectionMgr::Init(uint16_t maxCo
         mMaxOptimisticPipelinedRequests = maxOptimisticPipelinedRequests;
 
         mIsShuttingDown = false;
     }
 
     return EnsureSocketThreadTarget();
 }
 
+class BoolWrapper : public ARefBase
+{
+public:
+    BoolWrapper() : mBool(false) {}
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BoolWrapper)
+
+public: // intentional!
+    bool mBool;
+
+private:
+    virtual ~BoolWrapper() {}
+};
+
 nsresult
 nsHttpConnectionMgr::Shutdown()
 {
     LOG(("nsHttpConnectionMgr::Shutdown\n"));
 
-    bool shutdown = false;
+    RefPtr<BoolWrapper> shutdownWrapper = new BoolWrapper();
     {
         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
         // do nothing if already shutdown
         if (!mSocketThreadTarget)
             return NS_OK;
 
         nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgShutdown,
-                                0, &shutdown);
+                                0, shutdownWrapper);
 
         // release our reference to the STS to prevent further events
         // from being posted.  this is how we indicate that we are
         // shutting down.
         mIsShuttingDown = true;
         mSocketThreadTarget = 0;
 
         if (NS_FAILED(rv)) {
             NS_WARNING("unable to post SHUTDOWN message");
             return rv;
         }
     }
 
     // wait for shutdown event to complete
-    while (!shutdown)
+    while (!shutdownWrapper->mBool) {
         NS_ProcessNextEvent(NS_GetCurrentThread());
+    }
 
     return NS_OK;
 }
 
+class ConnEvent : public nsRunnable
+{
+public:
+    ConnEvent(nsHttpConnectionMgr *mgr,
+              nsConnEventHandler handler, int32_t iparam, ARefBase *vparam)
+        : mMgr(mgr)
+        , mHandler(handler)
+        , mIParam(iparam)
+        , mVParam(vparam) {}
+
+    NS_IMETHOD Run()
+    {
+        (mMgr->*mHandler)(mIParam, mVParam);
+        return NS_OK;
+    }
+
+private:
+    virtual ~ConnEvent() {}
+
+    RefPtr<nsHttpConnectionMgr>  mMgr;
+    nsConnEventHandler           mHandler;
+    int32_t                      mIParam;
+    RefPtr<ARefBase>             mVParam;
+};
+
 nsresult
-nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler, int32_t iparam, void *vparam)
+nsHttpConnectionMgr::PostEvent(nsConnEventHandler handler,
+                               int32_t iparam, ARefBase *vparam)
 {
     EnsureSocketThreadTarget();
 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
     nsresult rv;
     if (!mSocketThreadTarget) {
         NS_WARNING("cannot post event if not initialized");
         rv = NS_ERROR_NOT_INITIALIZED;
     }
     else {
-        nsCOMPtr<nsIRunnable> event = new nsConnEvent(this, handler, iparam, vparam);
+        nsCOMPtr<nsIRunnable> event = new ConnEvent(this, handler, iparam, vparam);
         rv = mSocketThreadTarget->Dispatch(event, NS_DISPATCH_NORMAL);
     }
     return rv;
 }
 
 void
 nsHttpConnectionMgr::PruneDeadConnectionsAfter(uint32_t timeInSeconds)
 {
@@ -288,47 +328,32 @@ nsHttpConnectionMgr::Observe(nsISupports
 
 
 //-----------------------------------------------------------------------------
 
 nsresult
 nsHttpConnectionMgr::AddTransaction(nsHttpTransaction *trans, int32_t priority)
 {
     LOG(("nsHttpConnectionMgr::AddTransaction [trans=%p %d]\n", trans, priority));
-
-    NS_ADDREF(trans);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
-    if (NS_FAILED(rv))
-        NS_RELEASE(trans);
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgNewTransaction, priority, trans);
 }
 
 nsresult
 nsHttpConnectionMgr::RescheduleTransaction(nsHttpTransaction *trans, int32_t priority)
 {
     LOG(("nsHttpConnectionMgr::RescheduleTransaction [trans=%p %d]\n", trans, priority));
-
-    NS_ADDREF(trans);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
-    if (NS_FAILED(rv))
-        NS_RELEASE(trans);
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgReschedTransaction, priority, trans);
 }
 
 nsresult
 nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason)
 {
     LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%p reason=%x]\n", trans, reason));
-
-    NS_ADDREF(trans);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
-                            static_cast<int32_t>(reason), trans);
-    if (NS_FAILED(rv))
-        NS_RELEASE(trans);
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction,
+                     static_cast<int32_t>(reason), trans);
 }
 
 nsresult
 nsHttpConnectionMgr::PruneDeadConnections()
 {
     return PostEvent(&nsHttpConnectionMgr::OnMsgPruneDeadConnections);
 }
 
@@ -345,61 +370,44 @@ nsHttpConnectionMgr::PruneNoTraffic()
 
 nsresult
 nsHttpConnectionMgr::VerifyTraffic()
 {
     LOG(("nsHttpConnectionMgr::VerifyTraffic\n"));
     return PostEvent(&nsHttpConnectionMgr::OnMsgVerifyTraffic);
 }
 
-
 nsresult
 nsHttpConnectionMgr::DoShiftReloadConnectionCleanup(nsHttpConnectionInfo *aCI)
 {
-    RefPtr<nsHttpConnectionInfo> connInfo(aCI);
-
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
-                            0, connInfo);
-    if (NS_SUCCEEDED(rv))
-        unused << connInfo.forget();
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup,
+                     0, aCI);
 }
 
-class SpeculativeConnectArgs
+class SpeculativeConnectArgs : public ARefBase
 {
-    virtual ~SpeculativeConnectArgs() {}
-
 public:
     SpeculativeConnectArgs() { mOverridesOK = false; }
-
-    // Added manually so we can use nsRefPtr without inheriting from
-    // nsISupports
-    NS_IMETHOD_(MozExternalRefCountType) AddRef(void);
-    NS_IMETHOD_(MozExternalRefCountType) Release(void);
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SpeculativeConnectArgs)
 
 public: // intentional!
     RefPtr<NullHttpTransaction> mTrans;
 
     bool mOverridesOK;
     uint32_t mParallelSpeculativeConnectLimit;
     bool mIgnoreIdle;
     bool mIgnorePossibleSpdyConnections;
     bool mIsFromPredictor;
     bool mAllow1918;
 
-    // As above, added manually so we can use nsRefPtr without inheriting from
-    // nsISupports
-protected:
-    ThreadSafeAutoRefCnt mRefCnt;
+private:
+    virtual ~SpeculativeConnectArgs() {}
     NS_DECL_OWNINGTHREAD
 };
 
-NS_IMPL_ADDREF(SpeculativeConnectArgs)
-NS_IMPL_RELEASE(SpeculativeConnectArgs)
-
 nsresult
 nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci,
                                         nsIInterfaceRequestor *callbacks,
                                         uint32_t caps,
                                         NullHttpTransaction *nullTransaction)
 {
     MOZ_ASSERT(NS_IsMainThread(), "nsHttpConnectionMgr::SpeculativeConnect called off main thread!");
 
@@ -439,118 +447,99 @@ nsHttpConnectionMgr::SpeculativeConnect(
             &args->mParallelSpeculativeConnectLimit);
         overrider->GetIgnoreIdle(&args->mIgnoreIdle);
         overrider->GetIgnorePossibleSpdyConnections(
             &args->mIgnorePossibleSpdyConnections);
         overrider->GetIsFromPredictor(&args->mIsFromPredictor);
         overrider->GetAllow1918(&args->mAllow1918);
     }
 
-    nsresult rv =
-        PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
-    if (NS_SUCCEEDED(rv))
-        unused << args.forget();
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgSpeculativeConnect, 0, args);
 }
 
 nsresult
 nsHttpConnectionMgr::GetSocketThreadTarget(nsIEventTarget **target)
 {
     EnsureSocketThreadTarget();
 
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     NS_IF_ADDREF(*target = mSocketThreadTarget);
     return NS_OK;
 }
 
 nsresult
 nsHttpConnectionMgr::ReclaimConnection(nsHttpConnection *conn)
 {
     LOG(("nsHttpConnectionMgr::ReclaimConnection [conn=%p]\n", conn));
-
-    NS_ADDREF(conn);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
-    if (NS_FAILED(rv))
-        NS_RELEASE(conn);
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgReclaimConnection, 0, conn);
 }
 
 // A structure used to marshall 2 pointers across the various necessary
 // threads to complete an HTTP upgrade.
-class nsCompleteUpgradeData
+class nsCompleteUpgradeData : public ARefBase
 {
 public:
-nsCompleteUpgradeData(nsAHttpConnection *aConn,
-                      nsIHttpUpgradeListener *aListener)
-    : mConn(aConn), mUpgradeListener(aListener) {}
+    nsCompleteUpgradeData(nsAHttpConnection *aConn,
+                          nsIHttpUpgradeListener *aListener)
+        : mConn(aConn)
+        , mUpgradeListener(aListener) { }
+
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCompleteUpgradeData)
 
     RefPtr<nsAHttpConnection> mConn;
     nsCOMPtr<nsIHttpUpgradeListener> mUpgradeListener;
+private:
+    virtual ~nsCompleteUpgradeData() { }
 };
 
 nsresult
 nsHttpConnectionMgr::CompleteUpgrade(nsAHttpConnection *aConn,
                                      nsIHttpUpgradeListener *aUpgradeListener)
 {
-    nsCompleteUpgradeData *data =
+    RefPtr<nsCompleteUpgradeData> data =
         new nsCompleteUpgradeData(aConn, aUpgradeListener);
-    nsresult rv;
-    rv = PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
-    if (NS_FAILED(rv))
-        delete data;
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgCompleteUpgrade, 0, data);
 }
 
 nsresult
 nsHttpConnectionMgr::UpdateParam(nsParamName name, uint16_t value)
 {
     uint32_t param = (uint32_t(name) << 16) | uint32_t(value);
-    return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam, 0,
-                     (void *)(uintptr_t) param);
+    return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateParam,
+                     static_cast<int32_t>(param), nullptr);
 }
 
 nsresult
 nsHttpConnectionMgr::ProcessPendingQ(nsHttpConnectionInfo *ci)
 {
     LOG(("nsHttpConnectionMgr::ProcessPendingQ [ci=%s]\n", ci->HashKey().get()));
-
-    NS_ADDREF(ci);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
-    if (NS_FAILED(rv))
-        NS_RELEASE(ci);
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, ci);
 }
 
 nsresult
 nsHttpConnectionMgr::ProcessPendingQ()
 {
     LOG(("nsHttpConnectionMgr::ProcessPendingQ [All CI]\n"));
     return PostEvent(&nsHttpConnectionMgr::OnMsgProcessPendingQ, 0, nullptr);
 }
 
 void
-nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket(int32_t, ARefBase *param)
 {
-    RefPtr<EventTokenBucket> tokenBucket =
-        dont_AddRef(static_cast<EventTokenBucket *>(param));
+    EventTokenBucket *tokenBucket = static_cast<EventTokenBucket *>(param);
     gHttpHandler->SetRequestTokenBucket(tokenBucket);
 }
 
 nsresult
 nsHttpConnectionMgr::UpdateRequestTokenBucket(EventTokenBucket *aBucket)
 {
-    RefPtr<EventTokenBucket> bucket(aBucket);
-
     // Call From main thread when a new EventTokenBucket has been made in order
     // to post the new value to the socket thread.
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
-                            0, bucket);
-    if (NS_SUCCEEDED(rv))
-        unused << bucket.forget();
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgUpdateRequestTokenBucket,
+                     0, aBucket);
 }
 
 PLDHashOperator
 nsHttpConnectionMgr::RemoveDeadConnections(const nsACString &key,
                 nsAutoPtr<nsConnectionEntry> &ent,
                 void *aArg)
 {
     if (ent->mIdleConns.Length()   == 0 &&
@@ -1191,62 +1180,57 @@ nsHttpConnectionMgr::SupportsPipelining(
     nsConnectionEntry *ent = mCT.Get(ci->HashKey());
     if (ent)
         return ent->SupportsPipelining();
     return false;
 }
 
 // nsHttpPipelineFeedback used to hold references across events
 
-class nsHttpPipelineFeedback
+class nsHttpPipelineFeedback : public ARefBase
 {
 public:
     nsHttpPipelineFeedback(nsHttpConnectionInfo *ci,
                            nsHttpConnectionMgr::PipelineFeedbackInfoType info,
                            nsHttpConnection *conn, uint32_t data)
         : mConnInfo(ci)
         , mConn(conn)
         , mInfo(info)
         , mData(data)
         {
         }
 
-    ~nsHttpPipelineFeedback()
-    {
-    }
 
     RefPtr<nsHttpConnectionInfo> mConnInfo;
     RefPtr<nsHttpConnection> mConn;
     nsHttpConnectionMgr::PipelineFeedbackInfoType mInfo;
     uint32_t mData;
+private:
+    ~nsHttpPipelineFeedback() {}
+    NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpPipelineFeedback)
 };
 
 void
 nsHttpConnectionMgr::PipelineFeedbackInfo(nsHttpConnectionInfo *ci,
                                           PipelineFeedbackInfoType info,
                                           nsHttpConnection *conn,
                                           uint32_t data)
 {
     if (!ci)
         return;
 
     // Post this to the socket thread if we are not running there already
     if (PR_GetCurrentThread() != gSocketThread) {
-        nsHttpPipelineFeedback *fb = new nsHttpPipelineFeedback(ci, info,
-                                                                conn, data);
-
-        nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgProcessFeedback,
-                                0, fb);
-        if (NS_FAILED(rv))
-            delete fb;
+        RefPtr<nsHttpPipelineFeedback> fb =
+            new nsHttpPipelineFeedback(ci, info, conn, data);
+        PostEvent(&nsHttpConnectionMgr::OnMsgProcessFeedback, 0, fb);
         return;
     }
 
     nsConnectionEntry *ent = mCT.Get(ci->HashKey());
-
     if (ent)
         ent->OnPipelineFeedbackInfo(info, conn, data);
 }
 
 void
 nsHttpConnectionMgr::ReportFailedToProcess(nsIURI *uri)
 {
     MOZ_ASSERT(uri);
@@ -1919,16 +1903,54 @@ nsHttpConnectionMgr::DispatchTransaction
         else
             AccumulateTimeDelta(Telemetry::TRANSACTION_WAIT_TIME_HTTP,
                 trans->GetPendingTime(), TimeStamp::Now());
         trans->SetPendingTime(false);
     }
     return rv;
 }
 
+//-----------------------------------------------------------------------------
+// ConnectionHandle
+//
+// thin wrapper around a real connection, used to keep track of references
+// to the connection to determine when the connection may be reused.  the
+// transaction (or pipeline) owns a reference to this handle.  this extra
+// layer of indirection greatly simplifies consumer code, avoiding the
+// need for consumer code to know when to give the connection back to the
+// connection manager.
+//
+class ConnectionHandle : public nsAHttpConnection
+{
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+    NS_DECL_NSAHTTPCONNECTION(mConn)
+
+    explicit ConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
+    nsHttpConnection *mConn;
+
+private:
+    virtual ~ConnectionHandle();
+};
+
+nsAHttpConnection *
+nsHttpConnectionMgr::MakeConnectionHandle(nsHttpConnection *aWrapped)
+{
+    return new ConnectionHandle(aWrapped);
+}
+
+ConnectionHandle::~ConnectionHandle()
+{
+    if (mConn) {
+        gHttpHandler->ReclaimConnection(mConn);
+        NS_RELEASE(mConn);
+    }
+}
+
+NS_IMPL_ISUPPORTS0(ConnectionHandle)
 
 // Use this method for dispatching nsAHttpTransction's. It can only safely be
 // used upon first use of a connection when NPN has not negotiated SPDY vs
 // HTTP/1 yet as multiplexing onto an existing SPDY session requires a
 // concrete nsHttpTransaction
 nsresult
 nsHttpConnectionMgr::DispatchAbstractTransaction(nsConnectionEntry *ent,
                                                  nsAHttpTransaction *aTrans,
@@ -1958,17 +1980,17 @@ nsHttpConnectionMgr::DispatchAbstractTra
             return rv;
         transaction = pipeline;
     }
     else {
         LOG(("   not using pipeline datastructure due to class solo.\n"));
         transaction = aTrans;
     }
 
-    RefPtr<nsConnectionHandle> handle = new nsConnectionHandle(conn);
+    RefPtr<ConnectionHandle> handle = new ConnectionHandle(conn);
 
     // give the transaction the indirect reference to the connection.
     transaction->SetConnection(handle);
 
     rv = conn->Activate(transaction, caps, priority);
     if (NS_FAILED(rv)) {
         LOG(("  conn->Activate failed [rv=%x]\n", rv));
         ent->mActiveConns.RemoveElement(conn);
@@ -2248,17 +2270,17 @@ nsHttpConnectionMgr::ProcessSpdyPendingQ
                                            void *closure)
 {
     nsHttpConnectionMgr *self = (nsHttpConnectionMgr *) closure;
     self->ProcessSpdyPendingQ(ent);
     return PL_DHASH_NEXT;
 }
 
 void
-nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, void *)
+nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ(int32_t, ARefBase *)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgProcessAllSpdyPendingQ\n"));
     mCT.Enumerate(ProcessSpdyPendingQCB, this);
 }
 
 nsHttpConnection *
 nsHttpConnectionMgr::GetSpdyPreferredConn(nsConnectionEntry *ent)
@@ -2289,17 +2311,17 @@ nsHttpConnectionMgr::GetSpdyPreferredCon
     }
 
     return conn;
 }
 
 //-----------------------------------------------------------------------------
 
 void
-nsHttpConnectionMgr::OnMsgShutdown(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgShutdown(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgShutdown\n"));
 
     mCT.Enumerate(ShutdownPassCB, this);
 
     if (mTimeoutTick) {
         mTimeoutTick->Cancel();
@@ -2312,76 +2334,72 @@ nsHttpConnectionMgr::OnMsgShutdown(int32
     }
     if (mTrafficTimer) {
       mTrafficTimer->Cancel();
       mTrafficTimer = nullptr;
     }
 
     // signal shutdown complete
     nsCOMPtr<nsIRunnable> runnable =
-        new nsConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
-                        0, param);
+        new ConnEvent(this, &nsHttpConnectionMgr::OnMsgShutdownConfirm,
+                      0, param);
     NS_DispatchToMainThread(runnable);
 }
 
 void
-nsHttpConnectionMgr::OnMsgShutdownConfirm(int32_t priority, void *param)
+nsHttpConnectionMgr::OnMsgShutdownConfirm(int32_t priority, ARefBase *param)
 {
     MOZ_ASSERT(NS_IsMainThread());
     LOG(("nsHttpConnectionMgr::OnMsgShutdownConfirm\n"));
 
-    bool *shutdown = static_cast<bool*>(param);
-    *shutdown = true;
+    BoolWrapper *shutdown = static_cast<BoolWrapper *>(param);
+    shutdown->mBool = true;
 }
 
 void
-nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, void *param)
+nsHttpConnectionMgr::OnMsgNewTransaction(int32_t priority, ARefBase *param)
 {
     LOG(("nsHttpConnectionMgr::OnMsgNewTransaction [trans=%p]\n", param));
 
-    nsHttpTransaction *trans = (nsHttpTransaction *) param;
+    nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
     trans->SetPriority(priority);
     nsresult rv = ProcessNewTransaction(trans);
     if (NS_FAILED(rv))
         trans->Close(rv); // for whatever its worth
-    NS_RELEASE(trans);
 }
 
 void
-nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, void *param)
+nsHttpConnectionMgr::OnMsgReschedTransaction(int32_t priority, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgReschedTransaction [trans=%p]\n", param));
 
-    nsHttpTransaction *trans = (nsHttpTransaction *) param;
+    nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
     trans->SetPriority(priority);
 
     nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(),
                                                    nullptr, trans);
 
     if (ent) {
         int32_t index = ent->mPendingQ.IndexOf(trans);
         if (index >= 0) {
             ent->mPendingQ.RemoveElementAt(index);
             InsertTransactionSorted(ent->mPendingQ, trans);
         }
     }
-
-    NS_RELEASE(trans);
 }
 
 void
-nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, void *param)
+nsHttpConnectionMgr::OnMsgCancelTransaction(int32_t reason, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param));
 
     nsresult closeCode = static_cast<nsresult>(reason);
-    RefPtr<nsHttpTransaction> trans =
-        dont_AddRef(static_cast<nsHttpTransaction *>(param));
+    nsHttpTransaction *trans = static_cast<nsHttpTransaction *>(param);
 
     //
     // if the transaction owns a connection and the transaction is not done,
     // then ask the connection to close the transaction.  otherwise, close the
     // transaction directly (removing it from the pending queue first).
     //
     RefPtr<nsAHttpConnection> conn(trans->Connection());
     if (conn && !trans->IsDone()) {
@@ -2389,17 +2407,17 @@ nsHttpConnectionMgr::OnMsgCancelTransact
     } else {
         nsConnectionEntry *ent =
             LookupConnectionEntry(trans->ConnectionInfo(), nullptr, trans);
 
         if (ent) {
             int32_t index = ent->mPendingQ.IndexOf(trans);
             if (index >= 0) {
                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]"
-                     " found in pending queue\n", trans.get()));
+                     " found in pending queue\n", trans));
                 ent->mPendingQ.RemoveElementAt(index);
                 nsHttpTransaction *temp = trans;
                 NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument!
             }
 
             // Abandon all half-open sockets belonging to the given transaction.
             for (uint32_t index = 0;
                  index < ent->mHalfOpens.Length();
@@ -2424,28 +2442,28 @@ nsHttpConnectionMgr::OnMsgCancelTransact
         for (uint32_t index = 0;
              ent && (index < ent->mActiveConns.Length());
              ++index) {
             nsHttpConnection *activeConn = ent->mActiveConns[index];
             nsAHttpTransaction *liveTransaction = activeConn->Transaction();
             if (liveTransaction && liveTransaction->IsNullTransaction()) {
                 LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p] "
                      "also canceling Null Transaction %p on conn %p\n",
-                     trans.get(), liveTransaction, activeConn));
+                     trans, liveTransaction, activeConn));
                 activeConn->CloseTransaction(liveTransaction, closeCode);
             }
         }
     }
 }
 
 void
-nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgProcessPendingQ(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-    nsHttpConnectionInfo *ci = (nsHttpConnectionInfo *) param;
+    nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
 
     if (!ci) {
         LOG(("nsHttpConnectionMgr::OnMsgProcessPendingQ [ci=nullptr]\n"));
         // Try and dispatch everything
         mCT.Enumerate(ProcessAllTransactionsCB, this);
         return;
     }
 
@@ -2454,40 +2472,32 @@ nsHttpConnectionMgr::OnMsgProcessPending
 
     // start by processing the queue identified by the given connection info.
     nsConnectionEntry *ent = mCT.Get(ci->HashKey());
     if (!(ent && ProcessPendingQForEntry(ent, false))) {
         // if we reach here, it means that we couldn't dispatch a transaction
         // for the specified connection info.  walk the connection table...
         mCT.Enumerate(ProcessOneTransactionCB, this);
     }
-
-    NS_RELEASE(ci);
 }
 
 nsresult
-nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *aCI, nsresult code)
+nsHttpConnectionMgr::CancelTransactions(nsHttpConnectionInfo *ci, nsresult code)
 {
-    RefPtr<nsHttpConnectionInfo> ci(aCI);
     LOG(("nsHttpConnectionMgr::CancelTransactions %s\n",ci->HashKey().get()));
 
     int32_t intReason = static_cast<int32_t>(code);
-    nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
-    if (NS_SUCCEEDED(rv)) {
-        unused << ci.forget();
-    }
-    return rv;
+    return PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransactions, intReason, ci);
 }
 
 void
-nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, void *param)
+nsHttpConnectionMgr::OnMsgCancelTransactions(int32_t code, ARefBase *param)
 {
     nsresult reason = static_cast<nsresult>(code);
-    RefPtr<nsHttpConnectionInfo> ci =
-        dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
+    nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
     nsConnectionEntry *ent = mCT.Get(ci->HashKey());
     LOG(("nsHttpConnectionMgr::OnMsgCancelTransactions %s %p\n",
          ci->HashKey().get(), ent));
     if (!ent) {
         return;
     }
 
     RefPtr<nsHttpTransaction> trans;
@@ -2497,44 +2507,44 @@ nsHttpConnectionMgr::OnMsgCancelTransact
              ci->HashKey().get(), ent, trans.get()));
         ent->mPendingQ.RemoveElementAt(i);
         trans->Close(reason);
         trans = nullptr;
     }
 }
 
 void
-nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, void *)
+nsHttpConnectionMgr::OnMsgPruneDeadConnections(int32_t, ARefBase *)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgPruneDeadConnections\n"));
 
     // Reset mTimeOfNextWakeUp so that we can find a new shortest value.
     mTimeOfNextWakeUp = UINT64_MAX;
 
     // check canreuse() for all idle connections plus any active connections on
     // connection entries that are using spdy.
     if (mNumIdleConns || (mNumActiveConns && gHttpHandler->IsSpdyEnabled()))
         mCT.Enumerate(PruneDeadConnectionsCB, this);
 }
 
 void
-nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, void *)
+nsHttpConnectionMgr::OnMsgPruneNoTraffic(int32_t, ARefBase *)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgPruneNoTraffic\n"));
 
     // Prune connections without traffic
     mCT.Enumerate(PruneNoTrafficCB, this);
 
     mPruningNoTraffic = false; // not pruning anymore
 }
 
 void
-nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, void *)
+nsHttpConnectionMgr::OnMsgVerifyTraffic(int32_t, ARefBase *)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgVerifyTraffic\n"));
 
     if (mPruningNoTraffic) {
       // Called in the time gap when the timeout to prune notraffic
       // connections has triggered but the pruning hasn't happened yet.
       return;
@@ -2556,36 +2566,35 @@ nsHttpConnectionMgr::OnMsgVerifyTraffic(
         mTrafficTimer->Init(this, gHttpHandler->NetworkChangedTimeout(),
                             nsITimer::TYPE_ONE_SHOT);
     } else {
         NS_WARNING("failed to create timer for VerifyTraffic!");
     }
 }
 
 void
-nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup(int32_t, ARefBase *param)
 {
     LOG(("nsHttpConnectionMgr::OnMsgDoShiftReloadConnectionCleanup\n"));
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
-    RefPtr<nsHttpConnectionInfo> ci =
-        dont_AddRef(static_cast<nsHttpConnectionInfo *>(param));
+    nsHttpConnectionInfo *ci = static_cast<nsHttpConnectionInfo *>(param);
 
     mCT.Enumerate(ClosePersistentConnectionsCB, this);
     if (ci)
         ResetIPFamilyPreference(ci);
 }
 
 void
-nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
     LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection [conn=%p]\n", param));
 
-    nsHttpConnection *conn = (nsHttpConnection *) param;
+    nsHttpConnection *conn = static_cast<nsHttpConnection *>(param);
 
     //
     // 1) remove the connection from the active list
     // 2) if keep-alive, add connection to idle list
     // 3) post event to process the pending transaction queue
     //
 
     nsConnectionEntry *ent = LookupConnectionEntry(conn->ConnectionInfo(),
@@ -2596,18 +2605,17 @@ nsHttpConnectionMgr::OnMsgReclaimConnect
         // future transactions. HTTP/2 tunnels work like this.
         ent = GetOrCreateConnectionEntry(conn->ConnectionInfo(), true);
         LOG(("nsHttpConnectionMgr::OnMsgReclaimConnection conn %p "
              "forced new hash entry %s\n",
              conn, conn->ConnectionInfo()->HashKey().get()));
     }
 
     MOZ_ASSERT(ent);
-    nsHttpConnectionInfo *ci = nullptr;
-    NS_ADDREF(ci = ent->mConnInfo);
+    RefPtr<nsHttpConnectionInfo> ci(ent->mConnInfo);
 
     // If the connection is in the active list, remove that entry
     // and the reference held by the mActiveConns list.
     // This is never the final reference on conn as the event context
     // is also holding one that is released at the end of this function.
 
     if (conn->EverUsedSpdy()) {
         // Spdy connections aren't reused in the traditional HTTP way in
@@ -2663,25 +2671,24 @@ nsHttpConnectionMgr::OnMsgReclaimConnect
         uint32_t timeToLive = conn->TimeToLive();
         if(!mTimer || NowInSeconds() + timeToLive < mTimeOfNextWakeUp)
             PruneDeadConnectionsAfter(timeToLive);
     } else {
         LOG(("  connection cannot be reused; closing connection\n"));
         conn->Close(NS_ERROR_ABORT);
     }
 
-    OnMsgProcessPendingQ(0, ci); // releases |ci|
-    NS_RELEASE(conn);
+    OnMsgProcessPendingQ(0, ci);
 }
 
 void
-nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgCompleteUpgrade(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-    nsCompleteUpgradeData *data = (nsCompleteUpgradeData *) param;
+    nsCompleteUpgradeData *data = static_cast<nsCompleteUpgradeData *>(param);
     LOG(("nsHttpConnectionMgr::OnMsgCompleteUpgrade "
          "this=%p conn=%p listener=%p\n", this, data->mConn.get(),
          data->mUpgradeListener.get()));
 
     nsCOMPtr<nsISocketTransport> socketTransport;
     nsCOMPtr<nsIAsyncInputStream> socketIn;
     nsCOMPtr<nsIAsyncOutputStream> socketOut;
 
@@ -2689,24 +2696,24 @@ nsHttpConnectionMgr::OnMsgCompleteUpgrad
     rv = data->mConn->TakeTransport(getter_AddRefs(socketTransport),
                                     getter_AddRefs(socketIn),
                                     getter_AddRefs(socketOut));
 
     if (NS_SUCCEEDED(rv))
         data->mUpgradeListener->OnTransportAvailable(socketTransport,
                                                      socketIn,
                                                      socketOut);
-    delete data;
 }
 
 void
-nsHttpConnectionMgr::OnMsgUpdateParam(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgUpdateParam(int32_t inParam, ARefBase *)
 {
-    uint16_t name  = (NS_PTR_TO_INT32(param) & 0xFFFF0000) >> 16;
-    uint16_t value =  NS_PTR_TO_INT32(param) & 0x0000FFFF;
+    uint32_t param = static_cast<uint32_t>(inParam);
+    uint16_t name  = ((param) & 0xFFFF0000) >> 16;
+    uint16_t value =  param & 0x0000FFFF;
 
     switch (name) {
     case MAX_CONNECTIONS:
         mMaxConns = value;
         break;
     case MAX_PERSISTENT_CONNECTIONS_PER_HOST:
         mMaxPersistConnsPerHost = value;
         break;
@@ -2730,23 +2737,21 @@ nsHttpConnectionMgr::OnMsgUpdateParam(in
 // nsHttpConnectionMgr::nsConnectionEntry
 nsHttpConnectionMgr::nsConnectionEntry::~nsConnectionEntry()
 {
     MOZ_COUNT_DTOR(nsConnectionEntry);
     gHttpHandler->ConnMgr()->RemovePreferredHash(this);
 }
 
 void
-nsHttpConnectionMgr::OnMsgProcessFeedback(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgProcessFeedback(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-    nsHttpPipelineFeedback *fb = (nsHttpPipelineFeedback *)param;
-
+    nsHttpPipelineFeedback *fb = static_cast<nsHttpPipelineFeedback *>(param);
     PipelineFeedbackInfo(fb->mConnInfo, fb->mInfo, fb->mConn, fb->mData);
-    delete fb;
 }
 
 // Read Timeout Tick handlers
 
 void
 nsHttpConnectionMgr::ActivateTimeoutTick()
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
@@ -2849,29 +2854,16 @@ nsHttpConnectionMgr::TimeoutTickCB(const
         }
     }
     if (ent->mHalfOpens.Length()) {
         self->mTimeoutTickNext = 1;
     }
     return PL_DHASH_NEXT;
 }
 
-//-----------------------------------------------------------------------------
-// nsHttpConnectionMgr::nsConnectionHandle
-
-nsHttpConnectionMgr::nsConnectionHandle::~nsConnectionHandle()
-{
-    if (mConn) {
-        gHttpHandler->ReclaimConnection(mConn);
-        NS_RELEASE(mConn);
-    }
-}
-
-NS_IMPL_ISUPPORTS0(nsHttpConnectionMgr::nsConnectionHandle)
-
 // GetOrCreateConnectionEntry finds a ent for a particular CI for use in
 // dispatching a transaction according to these rules
 // 1] use an ent that matches the ci that can be dispatched immediately
 // 2] otherwise use an ent of wildcard(ci) than can be dispatched immediately
 // 3] otherwise create an ent that matches ci and make new conn on it
 
 nsHttpConnectionMgr::nsConnectionEntry *
 nsHttpConnectionMgr::GetOrCreateConnectionEntry(nsHttpConnectionInfo *specificCI,
@@ -2902,46 +2894,44 @@ nsHttpConnectionMgr::GetOrCreateConnecti
         RefPtr<nsHttpConnectionInfo> clone(specificCI->Clone());
         specificEnt = new nsConnectionEntry(clone);
         mCT.Put(clone->HashKey(), specificEnt);
     }
     return specificEnt;
 }
 
 nsresult
-nsHttpConnectionMgr::nsConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
-                                                            nsHttpRequestHead *req,
-                                                            nsHttpResponseHead *resp,
-                                                            bool *reset)
+ConnectionHandle::OnHeadersAvailable(nsAHttpTransaction *trans,
+                                     nsHttpRequestHead *req,
+                                     nsHttpResponseHead *resp,
+                                     bool *reset)
 {
     return mConn->OnHeadersAvailable(trans, req, resp, reset);
 }
 
 void
-nsHttpConnectionMgr::nsConnectionHandle::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
+ConnectionHandle::CloseTransaction(nsAHttpTransaction *trans, nsresult reason)
 {
     mConn->CloseTransaction(trans, reason);
 }
 
 nsresult
-nsHttpConnectionMgr::
-nsConnectionHandle::TakeTransport(nsISocketTransport  **aTransport,
-                                  nsIAsyncInputStream **aInputStream,
-                                  nsIAsyncOutputStream **aOutputStream)
+ConnectionHandle::TakeTransport(nsISocketTransport  **aTransport,
+                                nsIAsyncInputStream **aInputStream,
+                                nsIAsyncOutputStream **aOutputStream)
 {
     return mConn->TakeTransport(aTransport, aInputStream, aOutputStream);
 }
 
 void
-nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, void *param)
+nsHttpConnectionMgr::OnMsgSpeculativeConnect(int32_t, ARefBase *param)
 {
     MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
 
-    RefPtr<SpeculativeConnectArgs> args =
-        dont_AddRef(static_cast<SpeculativeConnectArgs *>(param));
+    SpeculativeConnectArgs *args = static_cast<SpeculativeConnectArgs *>(param);
 
     LOG(("nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=%s]\n",
          args->mTrans->ConnectionInfo()->HashKey().get()));
 
     nsConnectionEntry *ent =
         GetOrCreateConnectionEntry(args->mTrans->ConnectionInfo(), false);
 
     // If spdy has previously made a preferred entry for this host via
@@ -2975,35 +2965,35 @@ nsHttpConnectionMgr::OnMsgSpeculativeCon
         CreateTransport(ent, args->mTrans, args->mTrans->Caps(), true, isFromPredictor, allow1918);
     }
     else {
         LOG(("  Transport not created due to existing connection count\n"));
     }
 }
 
 bool
-nsHttpConnectionMgr::nsConnectionHandle::IsPersistent()
+ConnectionHandle::IsPersistent()
 {
     return mConn->IsPersistent();
 }
 
 bool
-nsHttpConnectionMgr::nsConnectionHandle::IsReused()
+ConnectionHandle::IsReused()
 {
     return mConn->IsReused();
 }
 
 void
-nsHttpConnectionMgr::nsConnectionHandle::DontReuse()
+ConnectionHandle::DontReuse()
 {
     mConn->DontReuse();
 }
 
 nsresult
-nsHttpConnectionMgr::nsConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
+ConnectionHandle::PushBack(const char *buf, uint32_t bufLen)
 {
     return mConn->PushBack(buf, bufLen);
 }
 
 
 //////////////////////// nsHalfOpenSocket
 
 NS_IMPL_ISUPPORTS(nsHttpConnectionMgr::nsHalfOpenSocket,
@@ -3446,20 +3436,17 @@ nsHalfOpenSocket::OnOutputStreamReady(ns
             gHttpHandler->ConnMgr()->AddActiveConn(conn, mEnt);
             conn->Classify(nsAHttpTransaction::CLASS_SOLO);
             rv = gHttpHandler->ConnMgr()->
                 DispatchAbstractTransaction(mEnt, trans, mCaps, conn, 0);
         } else {
             // otherwise just put this in the persistent connection pool
             LOG(("nsHalfOpenSocket::OnOutputStreamReady no transaction match "
                  "returning conn %p to pool\n", conn.get()));
-            RefPtr<nsHttpConnection> copy(conn);
-            // forget() to effectively addref because onmsg*() will drop a ref
-            gHttpHandler->ConnMgr()->OnMsgReclaimConnection(
-                0, conn.forget().take());
+            gHttpHandler->ConnMgr()->OnMsgReclaimConnection(0, conn);
         }
     }
 
     return rv;
 }
 
 // method for nsITransportEventSink
 NS_IMETHODIMP
@@ -3564,41 +3551,41 @@ nsHttpConnectionMgr::nsHalfOpenSocket::G
         if (callbacks)
             return callbacks->GetInterface(iid, result);
     }
     return NS_ERROR_NO_INTERFACE;
 }
 
 
 nsHttpConnection *
-nsHttpConnectionMgr::nsConnectionHandle::TakeHttpConnection()
+ConnectionHandle::TakeHttpConnection()
 {
     // return our connection object to the caller and clear it internally
     // do not drop our reference - the caller now owns it.
 
     MOZ_ASSERT(mConn);
     nsHttpConnection *conn = mConn;
     mConn = nullptr;
     return conn;
 }
 
 uint32_t
-nsHttpConnectionMgr::nsConnectionHandle::CancelPipeline(nsresult reason)
+ConnectionHandle::CancelPipeline(nsresult reason)
 {
     // no pipeline to cancel
     return 0;
 }
 
 nsAHttpTransaction::Classifier
-nsHttpConnectionMgr::nsConnectionHandle::Classification()
+ConnectionHandle::Classification()
 {
     if (mConn)
         return mConn->Classification();
 
-    LOG(("nsConnectionHandle::Classification this=%p "
+    LOG(("ConnectionHandle::Classification this=%p "
          "has null mConn using CLASS_SOLO default", this));
     return nsAHttpTransaction::CLASS_SOLO;
 }
 
 // nsConnectionEntry
 
 nsHttpConnectionMgr::
 nsConnectionEntry::nsConnectionEntry(nsHttpConnectionInfo *ci)
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -12,30 +12,35 @@
 #include "nsThreadUtils.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #include "nsAutoPtr.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 #include "AlternateServices.h"
+#include "ARefBase.h"
 
 #include "nsIObserver.h"
 #include "nsITimer.h"
 
 class nsIHttpUpgradeListener;
 
 namespace mozilla {
 namespace net {
 class EventTokenBucket;
 class NullHttpTransaction;
 struct HttpRetParams;
 
 //-----------------------------------------------------------------------------
 
+// message handlers have this signature
+class nsHttpConnectionMgr;
+typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, ARefBase *);
+
 class nsHttpConnectionMgr final : public nsIObserver
                                 , public AltSvcCache
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
     // parameter names
@@ -384,42 +389,19 @@ private:
         bool mPreferIPv6 : 1;
 
         // Set the IP family preference flags according the connected family
         void RecordIPFamilyPreference(uint16_t family);
         // Resets all flags to their default values
         void ResetIPFamilyPreference();
     };
 
-    // nsConnectionHandle
-    //
-    // thin wrapper around a real connection, used to keep track of references
-    // to the connection to determine when the connection may be reused.  the
-    // transaction (or pipeline) owns a reference to this handle.  this extra
-    // layer of indirection greatly simplifies consumer code, avoiding the
-    // need for consumer code to know when to give the connection back to the
-    // connection manager.
-    //
-    class nsConnectionHandle : public nsAHttpConnection
-    {
-        virtual ~nsConnectionHandle();
+public:
+    static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped);
 
-    public:
-        NS_DECL_THREADSAFE_ISUPPORTS
-        NS_DECL_NSAHTTPCONNECTION(mConn)
-
-        explicit nsConnectionHandle(nsHttpConnection *conn) { NS_ADDREF(mConn = conn); }
-
-        nsHttpConnection *mConn;
-    };
-public:
-    static nsAHttpConnection *MakeConnectionHandle(nsHttpConnection *aWrapped)
-    {
-        return new nsConnectionHandle(aWrapped);
-    }
 private:
 
     // nsHalfOpenSocket is used to hold the state of an opening TCP socket
     // while we wait for it to establish and bind it to a connection
 
     class nsHalfOpenSocket final : public nsIOutputStreamCallback,
                                    public nsITransportEventSink,
                                    public nsIInterfaceRequestor,
@@ -517,17 +499,17 @@ private:
 
     // connection limits
     uint16_t mMaxConns;
     uint16_t mMaxPersistConnsPerHost;
     uint16_t mMaxPersistConnsPerProxy;
     uint16_t mMaxRequestDelay; // in seconds
     uint16_t mMaxPipelinedRequests;
     uint16_t mMaxOptimisticPipelinedRequests;
-    bool mIsShuttingDown;
+    Atomic<bool, mozilla::Relaxed> mIsShuttingDown;
 
     //-------------------------------------------------------------------------
     // NOTE: these members are only accessed on the socket transport thread
     //-------------------------------------------------------------------------
 
     static PLDHashOperator ProcessOneTransactionCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
     static PLDHashOperator ProcessAllTransactionsCB(const nsACString &, nsAutoPtr<nsConnectionEntry> &, void *);
 
@@ -589,82 +571,40 @@ private:
                                              nsHttpConnection *conn,
                                              nsHttpTransaction *trans);
 
     void               ProcessSpdyPendingQ(nsConnectionEntry *ent);
     static PLDHashOperator ProcessSpdyPendingQCB(
         const nsACString &key, nsAutoPtr<nsConnectionEntry> &ent,
         void *closure);
 
-    // message handlers have this signature
-    typedef void (nsHttpConnectionMgr:: *nsConnEventHandler)(int32_t, void *);
-
-    // nsConnEvent
-    //
-    // subclass of nsRunnable used to marshall events to the socket transport
-    // thread.  this class is used to implement PostEvent.
-    //
-    class nsConnEvent;
-    friend class nsConnEvent;
-    class nsConnEvent : public nsRunnable
-    {
-    public:
-        nsConnEvent(nsHttpConnectionMgr *mgr,
-                    nsConnEventHandler handler,
-                    int32_t iparam,
-                    void *vparam)
-            : mMgr(mgr)
-            , mHandler(handler)
-            , mIParam(iparam)
-            , mVParam(vparam)
-        {
-            NS_ADDREF(mMgr);
-        }
-
-        NS_IMETHOD Run()
-        {
-            (mMgr->*mHandler)(mIParam, mVParam);
-            return NS_OK;
-        }
-
-    private:
-        virtual ~nsConnEvent()
-        {
-            NS_RELEASE(mMgr);
-        }
-
-        nsHttpConnectionMgr *mMgr;
-        nsConnEventHandler   mHandler;
-        int32_t              mIParam;
-        void                *mVParam;
-    };
-
+    // used to marshall events to the socket transport thread.
     nsresult PostEvent(nsConnEventHandler  handler,
                        int32_t             iparam = 0,
-                       void               *vparam = nullptr);
+                       ARefBase            *vparam = nullptr);
 
     // message handlers
-    void OnMsgShutdown             (int32_t, void *);
-    void OnMsgShutdownConfirm      (int32_t, void *);
-    void OnMsgNewTransaction       (int32_t, void *);
-    void OnMsgReschedTransaction   (int32_t, void *);
-    void OnMsgCancelTransaction    (int32_t, void *);
-    void OnMsgCancelTransactions   (int32_t, void *);
-    void OnMsgProcessPendingQ      (int32_t, void *);
-    void OnMsgPruneDeadConnections (int32_t, void *);
-    void OnMsgSpeculativeConnect   (int32_t, void *);
-    void OnMsgReclaimConnection    (int32_t, void *);
-    void OnMsgCompleteUpgrade      (int32_t, void *);
-    void OnMsgUpdateParam          (int32_t, void *);
-    void OnMsgDoShiftReloadConnectionCleanup (int32_t, void *);
-    void OnMsgProcessFeedback      (int32_t, void *);
-    void OnMsgProcessAllSpdyPendingQ (int32_t, void *);
-    void OnMsgUpdateRequestTokenBucket (int32_t, void *);
-    void OnMsgVerifyTraffic (int32_t, void *);
-    void OnMsgPruneNoTraffic (int32_t, void *);
+    void OnMsgShutdown             (int32_t, ARefBase *);
+    void OnMsgShutdownConfirm      (int32_t, ARefBase *);
+    void OnMsgNewTransaction       (int32_t, ARefBase *);
+    void OnMsgReschedTransaction   (int32_t, ARefBase *);
+    void OnMsgCancelTransaction    (int32_t, ARefBase *);
+    void OnMsgCancelTransactions   (int32_t, ARefBase *);
+    void OnMsgProcessPendingQ      (int32_t, ARefBase *);
+    void OnMsgPruneDeadConnections (int32_t, ARefBase *);
+    void OnMsgSpeculativeConnect   (int32_t, ARefBase *);
+    void OnMsgReclaimConnection    (int32_t, ARefBase *);
+    void OnMsgCompleteUpgrade      (int32_t, ARefBase *);
+    void OnMsgUpdateParam          (int32_t, ARefBase *);
+    void OnMsgDoShiftReloadConnectionCleanup (int32_t, ARefBase *);
+    void OnMsgProcessFeedback      (int32_t, ARefBase *);
+    void OnMsgProcessAllSpdyPendingQ (int32_t, ARefBase *);
+    void OnMsgUpdateRequestTokenBucket (int32_t, ARefBase *);
+    void OnMsgVerifyTraffic (int32_t, ARefBase *);
+    void OnMsgPruneNoTraffic (int32_t, ARefBase *);
 
     // Total number of active connections in all of the ConnectionEntry objects
     // that are accessed from mCT connection table.
     uint16_t mNumActiveConns;
     // Total number of idle connections in all of the ConnectionEntry objects
     // that are accessed from mCT connection table.
     uint16_t mNumIdleConns;
     // Total number of spdy connections which are a subset of the active conns
@@ -706,17 +646,17 @@ private:
 
     // Read Timeout Tick handlers
     void TimeoutTick();
     static PLDHashOperator TimeoutTickCB(const nsACString &key,
                                          nsAutoPtr<nsConnectionEntry> &ent,
                                          void *closure);
 
     // For diagnostics
-    void OnMsgPrintDiagnostics(int32_t, void *);
+    void OnMsgPrintDiagnostics(int32_t, ARefBase *);
     static PLDHashOperator PrintDiagnosticsCB(const nsACString &key,
                                               nsAutoPtr<nsConnectionEntry> &ent,
                                               void *closure);
     nsCString mLogData;
 };
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/http/nsHttpTransaction.h
+++ b/netwerk/protocol/http/nsHttpTransaction.h
@@ -11,16 +11,17 @@
 #include "nsAHttpConnection.h"
 #include "EventTokenBucket.h"
 #include "nsCOMPtr.h"
 #include "nsThreadUtils.h"
 #include "nsIInterfaceRequestor.h"
 #include "TimingStruct.h"
 #include "Http2Push.h"
 #include "mozilla/net/DNS.h"
+#include "ARefBase.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkInterface.h"
 #include "nsProxyRelease.h"
 #endif
 
 //-----------------------------------------------------------------------------
 
@@ -40,16 +41,17 @@ class nsHttpResponseHead;
 // nsHttpTransaction represents a single HTTP transaction.  It is thread-safe,
 // intended to run on the socket thread.
 //-----------------------------------------------------------------------------
 
 class nsHttpTransaction final : public nsAHttpTransaction
                               , public ATokenBucketEvent
                               , public nsIInputStreamCallback
                               , public nsIOutputStreamCallback
+                              , public ARefBase
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSAHTTPTRANSACTION
     NS_DECL_NSIINPUTSTREAMCALLBACK
     NS_DECL_NSIOUTPUTSTREAMCALLBACK
 
     nsHttpTransaction();
--- a/testing/marionette/client/marionette/__init__.py
+++ b/testing/marionette/client/marionette/__init__.py
@@ -1,28 +1,36 @@
 # 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/.
 
 
 __version__ = '1.0.0'
 
-from .marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest
+from .marionette_test import (
+    CommonTestCase,
+    expectedFailure,
+    MarionetteJSTestCase,
+    MarionetteTestCase,
+    skip,
+    SkipTest,
+    skip_unless_protocol,
+)
 from .runner import (
-        B2GTestCaseMixin,
-        B2GTestResultMixin,
-        BaseMarionetteArguments,
-        BaseMarionetteTestRunner,
-        BrowserMobProxyTestCaseMixin,
-        EnduranceArguments,
-        EnduranceTestCaseMixin,
-        HTMLReportingArguments,
-        HTMLReportingTestResultMixin,
-        HTMLReportingTestRunnerMixin,
-        Marionette,
-        MarionetteTest,
-        MarionetteTestResult,
-        MarionetteTextTestRunner,
-        MemoryEnduranceTestCaseMixin,
-        TestManifest,
-        TestResult,
-        TestResultCollection
+    B2GTestCaseMixin,
+    B2GTestResultMixin,
+    BaseMarionetteArguments,
+    BaseMarionetteTestRunner,
+    BrowserMobProxyTestCaseMixin,
+    EnduranceArguments,
+    EnduranceTestCaseMixin,
+    HTMLReportingArguments,
+    HTMLReportingTestResultMixin,
+    HTMLReportingTestRunnerMixin,
+    Marionette,
+    MarionetteTest,
+    MarionetteTestResult,
+    MarionetteTextTestRunner,
+    MemoryEnduranceTestCaseMixin,
+    TestManifest,
+    TestResult,
+    TestResultCollection,
 )
--- a/testing/marionette/client/marionette/marionette_test.py
+++ b/testing/marionette/client/marionette/marionette_test.py
@@ -51,19 +51,17 @@ class _ExpectedFailure(Exception):
 
 class _UnexpectedSuccess(Exception):
     """
     The test was supposed to fail, but it didn't!
     """
     pass
 
 def skip(reason):
-    """
-    Unconditionally skip a test.
-    """
+    """Unconditionally skip a test."""
     def decorator(test_item):
         if not isinstance(test_item, (type, types.ClassType)):
             @functools.wraps(test_item)
             def skip_wrapper(*args, **kwargs):
                 raise SkipTest(reason)
             test_item = skip_wrapper
 
         test_item.__unittest_skip__ = True
@@ -76,22 +74,28 @@ def expectedFailure(func):
     def wrapper(*args, **kwargs):
         try:
             func(*args, **kwargs)
         except Exception:
             raise _ExpectedFailure(sys.exc_info())
         raise _UnexpectedSuccess
     return wrapper
 
+def skip_if_desktop(target):
+    def wrapper(self, *args, **kwargs):
+        if self.marionette.session_capabilities.get('b2g') is None:
+            raise SkipTest('skipping due to desktop')
+        return target(self, *args, **kwargs)
+    return wrapper
+
 def skip_if_b2g(target):
     def wrapper(self, *args, **kwargs):
         if self.marionette.session_capabilities.get('b2g') == True:
             raise SkipTest('skipping due to b2g')
         return target(self, *args, **kwargs)
-
     return wrapper
 
 def skip_if_e10s(target):
     def wrapper(self, *args, **kwargs):
         with self.marionette.using_context('chrome'):
             multi_process_browser = self.marionette.execute_script("""
             try {
               return Services.appinfo.browserTabsRemoteAutostart;
@@ -99,16 +103,29 @@ def skip_if_e10s(target):
               return false;
             }""")
 
         if multi_process_browser:
             raise SkipTest('skipping due to e10s')
         return target(self, *args, **kwargs)
     return wrapper
 
+def skip_unless_protocol(predicate):
+    """Given a predicate passed the current protocol level, skip the
+    test if the predicate does not match."""
+    def decorator(test_item):
+        @functools.wraps(test_item)
+        def skip_wrapper(self):
+            level = self.marionette.client.protocol
+            if not predicate(level):
+                raise SkipTest('skipping because protocol level is %s' % level)
+            return self
+        return skip_wrapper
+    return decorator
+
 def parameterized(func_suffix, *args, **kwargs):
     """
     A decorator that can generate methods given a base method and some data.
 
     **func_suffix** is used as a suffix for the new created method and must be
     unique given a base method. if **func_suffix** countains characters that
     are not allowed in normal python function name, these characters will be
     replaced with "_".
--- a/testing/marionette/client/marionette/tests/unit/test_emulator.py
+++ b/testing/marionette/client/marionette/tests/unit/test_emulator.py
@@ -1,60 +1,60 @@
 # 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/.
 
-from marionette import MarionetteTestCase
-from marionette_driver.errors import MarionetteException
+from unittest import skip
+
+from marionette.marionette_test import MarionetteTestCase, skip_if_desktop, skip_unless_protocol
+from marionette_driver.errors import MarionetteException, JavascriptException
 
 
 class TestEmulatorContent(MarionetteTestCase):
-
+    @skip_if_desktop
     def test_emulator_cmd(self):
         self.marionette.set_script_timeout(10000)
         expected = ["<build>",
                     "OK"]
         result = self.marionette.execute_async_script("""
         runEmulatorCmd("avd name", marionetteScriptFinished)
         """);
         self.assertEqual(result, expected)
 
+    @skip_if_desktop
     def test_emulator_shell(self):
         self.marionette.set_script_timeout(10000)
         expected = ["Hello World!"]
         result = self.marionette.execute_async_script("""
         runEmulatorShell(["echo", "Hello World!"], marionetteScriptFinished)
         """);
         self.assertEqual(result, expected)
 
+    @skip_if_desktop
     def test_emulator_order(self):
         self.marionette.set_script_timeout(10000)
         self.assertRaises(MarionetteException,
                           self.marionette.execute_async_script,
         """runEmulatorCmd("gsm status", function(result) {});
            marionetteScriptFinished(true);
         """);
 
 
 class TestEmulatorChrome(TestEmulatorContent):
-
     def setUp(self):
         super(TestEmulatorChrome, self).setUp()
         self.marionette.set_context("chrome")
 
 
 class TestEmulatorScreen(MarionetteTestCase):
-
-    def setUp(self):
-        MarionetteTestCase.setUp(self)
-
+    @skip_if_desktop
+    def test_emulator_orientation(self):
         self.screen = self.marionette.emulator.screen
         self.screen.initialize()
 
-    def test_emulator_orientation(self):
         self.assertEqual(self.screen.orientation, self.screen.SO_PORTRAIT_PRIMARY,
                          'Orientation has been correctly initialized.')
 
         self.screen.orientation = self.screen.SO_PORTRAIT_SECONDARY
         self.assertEqual(self.screen.orientation, self.screen.SO_PORTRAIT_SECONDARY,
                          'Orientation has been set to portrait-secondary')
 
         self.screen.orientation = self.screen.SO_LANDSCAPE_PRIMARY
@@ -63,8 +63,75 @@ class TestEmulatorScreen(MarionetteTestC
 
         self.screen.orientation = self.screen.SO_LANDSCAPE_SECONDARY
         self.assertEqual(self.screen.orientation, self.screen.SO_LANDSCAPE_SECONDARY,
                          'Orientation has been set to landscape-secondary')
 
         self.screen.orientation = self.screen.SO_PORTRAIT_PRIMARY
         self.assertEqual(self.screen.orientation, self.screen.SO_PORTRAIT_PRIMARY,
                          'Orientation has been set to portrait-primary')
+
+
+class TestEmulatorCallbacks(MarionetteTestCase):
+    def setUp(self):
+        MarionetteTestCase.setUp(self)
+        self.original_emulator_cmd = self.marionette._emulator_cmd
+        self.original_emulator_shell = self.marionette._emulator_shell
+        self.marionette._emulator_cmd = self.mock_emulator_cmd
+        self.marionette._emulator_shell = self.mock_emulator_shell
+
+    def tearDown(self):
+        self.marionette._emulator_cmd = self.original_emulator_cmd
+        self.marionette._emulator_shell = self.original_emulator_shell
+
+    def mock_emulator_cmd(self, *args):
+        return self.marionette._send_emulator_result("cmd response")
+
+    def mock_emulator_shell(self, *args):
+        return self.marionette._send_emulator_result("shell response")
+
+    def _execute_emulator(self, action, args):
+        script = "%s(%s, function(res) { marionetteScriptFinished(res); })" % (action, args)
+        return self.marionette.execute_async_script(script)
+
+    def emulator_cmd(self, cmd):
+        return self._execute_emulator("runEmulatorCmd", escape(cmd))
+
+    def emulator_shell(self, *args):
+        js_args = ", ".join(map(escape, args))
+        js_args = "[%s]" % js_args
+        return self._execute_emulator("runEmulatorShell", js_args)
+
+    def test_emulator_cmd_content(self):
+        with self.marionette.using_context("content"):
+            res = self.emulator_cmd("yo")
+            self.assertEqual("cmd response", res)
+
+    def test_emulator_shell_content(self):
+        with self.marionette.using_context("content"):
+            res = self.emulator_shell("first", "second")
+            self.assertEqual("shell response", res)
+
+    @skip_unless_protocol(lambda level: level >= 3)
+    def test_emulator_result_error_content(self):
+        with self.marionette.using_context("content"):
+            with self.assertRaisesRegexp(JavascriptException, "TypeError"):
+                self.marionette.execute_async_script("runEmulatorCmd()")
+
+    def test_emulator_cmd_chrome(self):
+        with self.marionette.using_context("chrome"):
+            res = self.emulator_cmd("yo")
+            self.assertEqual("cmd response", res)
+
+    def test_emulator_shell_chrome(self):
+        with self.marionette.using_context("chrome"):
+            res = self.emulator_shell("first", "second")
+            self.assertEqual("shell response", res)
+
+    @skip_unless_protocol(lambda level: level >= 3)
+    def test_emulator_result_error_chrome(self):
+        with self.marionette.using_context("chrome"):
+            with self.assertRaisesRegexp(JavascriptException, "TypeError"):
+                self.marionette.execute_async_script("runEmulatorCmd()")
+
+
+def escape(word):
+    return "'%s'" % word
--- a/testing/marionette/client/marionette/tests/unit/test_switch_frame.py
+++ b/testing/marionette/client/marionette/tests/unit/test_switch_frame.py
@@ -1,13 +1,14 @@
 # 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/.
 
 from marionette import MarionetteTestCase
+from marionette_driver.by import By
 from marionette_driver.errors import (JavascriptException,
                                       NoSuchFrameException)
 
 
 class TestSwitchFrame(MarionetteTestCase):
     def test_switch_simple(self):
         start_url = "test_iframe.html"
         verify_title = "Marionette IFrame Test"
@@ -129,8 +130,61 @@ class TestSwitchFrame(MarionetteTestCase
         frame_html = self.marionette.absolute_url("frameset.html")
         self.marionette.navigate(frame_html)
         frame = self.marionette.find_element("name", "third")
         self.marionette.switch_to_frame(frame)
         self.assertEqual("Unique title", self.marionette.title)
         test_html = self.marionette.absolute_url("test.html")
         self.marionette.navigate(test_html)
         self.assertEqual("Marionette Test", self.marionette.title)
+
+    def test_switch_to_parent_frame(self):
+        frame_html = self.marionette.absolute_url("frameset.html")
+        self.marionette.navigate(frame_html)
+        frame = self.marionette.find_element("name", "third")
+        self.marionette.switch_to_frame(frame)
+
+        # If we don't find the following element we aren't on the right page
+        self.marionette.find_element(By.ID, "checky")
+        form_page_title = self.marionette.execute_script("return document.title")
+        self.assertEqual("We Leave From Here", form_page_title)
+
+        self.marionette.switch_to_parent_frame()
+
+        current_page_title = self.marionette.execute_script("return document.title")
+        self.assertEqual("Unique title", current_page_title)
+
+    def test_switch_to_parent_frame_from_default_context_is_a_noop(self):
+        formpage = self.marionette.absolute_url("formPage.html")
+        self.marionette.navigate(formpage)
+
+        self.marionette.switch_to_parent_frame()
+
+        form_page_title = self.marionette.execute_script("return document.title")
+        self.assertEqual("We Leave From Here", form_page_title)
+
+    def test_should_be_able_to_switch_to_parent_from_second_level(self):
+        frame_html = self.marionette.absolute_url("frameset.html")
+        self.marionette.navigate(frame_html)
+        frame = self.marionette.find_element(By.NAME, "fourth")
+        self.marionette.switch_to_frame(frame)
+
+        second_level = self.marionette.find_element(By.NAME, "child1")
+        self.marionette.switch_to_frame(second_level)
+        self.marionette.find_element(By.NAME, "myCheckBox")
+
+        self.marionette.switch_to_parent_frame()
+
+        second_level = self.marionette.find_element(By.NAME, "child1")
+
+    def test_should_be_able_to_switch_to_parent_from_iframe(self):
+        frame_html = self.marionette.absolute_url("test_iframe.html")
+        self.marionette.navigate(frame_html)
+        frame = self.marionette.find_element(By.ID, "test_iframe")
+        self.marionette.switch_to_frame(frame)
+
+        current_page_title = self.marionette.execute_script("return document.title")
+        self.assertEqual("Marionette Test", current_page_title)
+
+        self.marionette.switch_to_parent_frame()
+
+        parent_page_title = self.marionette.execute_script("return document.title")
+        self.assertEqual("Marionette IFrame Test", parent_page_title)
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_transport.py
@@ -0,0 +1,181 @@
+# 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/.
+
+import json
+from marionette import MarionetteTestCase, skip_unless_protocol
+from marionette_transport import (
+    Command,
+    Proto2Command,
+    Proto2Response,
+    Response
+)
+
+get_current_url = ("getCurrentUrl", None)
+execute_script = ("executeScript", {"script": "return 42"})
+
+
+class TestMessageSequencing(MarionetteTestCase):
+    @property
+    def last_id(self):
+        return self.marionette.client.last_id
+
+    @last_id.setter
+    def last_id(self, new_id):
+        self.marionette.client.last_id = new_id
+
+    def send(self, name, params):
+        self.last_id = self.last_id + 1
+        cmd = Command(self.last_id, name, params)
+        self.marionette.client.send(cmd)
+        return self.last_id
+
+    @skip_unless_protocol(lambda level: level >= 3)
+    def test_discard_older_messages(self):
+        first = self.send(*get_current_url)
+        second = self.send(*execute_script)
+        resp = self.marionette.client.receive()
+        self.assertEqual(second, resp.id)
+
+    @skip_unless_protocol(lambda level: level >= 3)
+    def test_last_id_incremented(self):
+        before = self.last_id
+        self.send(*get_current_url)
+        self.assertGreater(self.last_id, before)
+
+
+class MessageTestCase(MarionetteTestCase):
+    def assert_attr(self, obj, attr):
+        self.assertTrue(hasattr(obj, attr),
+                        "object does not have attribute %s" % attr)
+
+
+class TestCommand(MessageTestCase):
+    def create(self, msgid="msgid", name="name", params="params"):
+        return Command(msgid, name, params)
+
+    def test_initialise(self):
+        cmd = self.create()
+        self.assert_attr(cmd, "id")
+        self.assert_attr(cmd, "name")
+        self.assert_attr(cmd, "params")
+        self.assertEqual("msgid", cmd.id)
+        self.assertEqual("name", cmd.name)
+        self.assertEqual("params", cmd.params)
+
+    def test_stringify(self):
+        cmd = self.create()
+        string = str(cmd)
+        self.assertIn("Command", string)
+        self.assertIn("id=msgid", string)
+        self.assertIn("name=name", string)
+        self.assertIn("params=params", string)
+
+    def test_to_msg(self):
+        cmd = self.create()
+        msg = json.loads(cmd.to_msg())
+        self.assertEquals(msg[0], Command.TYPE)
+        self.assertEquals(msg[1], "msgid")
+        self.assertEquals(msg[2], "name")
+        self.assertEquals(msg[3], "params")
+
+    def test_from_msg(self):
+        msg = [Command.TYPE, "msgid", "name", "params"]
+        payload = json.dumps(msg)
+        cmd = Command.from_msg(payload)
+        self.assertEquals(msg[1], cmd.id)
+        self.assertEquals(msg[2], cmd.name)
+        self.assertEquals(msg[3], cmd.params)
+
+
+class TestResponse(MessageTestCase):
+    def create(self, msgid="msgid", error="error", result="result"):
+        return Response(msgid, error, result)
+
+    def test_initialise(self):
+        resp = self.create()
+        self.assert_attr(resp, "id")
+        self.assert_attr(resp, "error")
+        self.assert_attr(resp, "result")
+        self.assertEqual("msgid", resp.id)
+        self.assertEqual("error", resp.error)
+        self.assertEqual("result", resp.result)
+
+    def test_stringify(self):
+        resp = self.create()
+        string = str(resp)
+        self.assertIn("Response", string)
+        self.assertIn("id=msgid", string)
+        self.assertIn("error=error", string)
+        self.assertIn("result=result", string)
+
+    def test_to_msg(self):
+        resp = self.create()
+        msg = json.loads(resp.to_msg())
+        self.assertEquals(msg[0], Response.TYPE)
+        self.assertEquals(msg[1], "msgid")
+        self.assertEquals(msg[2], "error")
+        self.assertEquals(msg[3], "result")
+
+    def test_from_msg(self):
+        msg = [Response.TYPE, "msgid", "error", "result"]
+        payload = json.dumps(msg)
+        resp = Response.from_msg(payload)
+        self.assertEquals(msg[1], resp.id)
+        self.assertEquals(msg[2], resp.error)
+        self.assertEquals(msg[3], resp.result)
+
+
+class TestProto2Command(MessageTestCase):
+    def create(self, name="name", params="params"):
+        return Proto2Command(name, params)
+
+    def test_initialise(self):
+        cmd = self.create()
+        self.assert_attr(cmd, "id")
+        self.assert_attr(cmd, "name")
+        self.assert_attr(cmd, "params")
+        self.assertEqual(None, cmd.id)
+        self.assertEqual("name", cmd.name)
+        self.assertEqual("params", cmd.params)
+
+    def test_from_data_emulator_cmd(self):
+        data = {"emulator_cmd": "emulator_cmd"}
+        cmd = Proto2Command.from_data(data)
+        self.assertEqual("runEmulatorCmd", cmd.name)
+        self.assertEqual(data, cmd.params)
+
+    def test_from_data_emulator_shell(self):
+        data = {"emulator_shell": "emulator_shell"}
+        cmd = Proto2Command.from_data(data)
+        self.assertEqual("runEmulatorShell", cmd.name)
+        self.assertEqual(data, cmd.params)
+
+    def test_from_data_unknown(self):
+        with self.assertRaises(ValueError):
+            cmd = Proto2Command.from_data({})
+
+
+class TestProto2Response(MessageTestCase):
+    def create(self, error="error", result="result"):
+        return Proto2Response(error, result)
+
+    def test_initialise(self):
+        resp = self.create()
+        self.assert_attr(resp, "id")
+        self.assert_attr(resp, "error")
+        self.assert_attr(resp, "result")
+        self.assertEqual(None, resp.id)
+        self.assertEqual("error", resp.error)
+        self.assertEqual("result", resp.result)
+
+    def test_from_data_error(self):
+        data = {"error": "error"}
+        resp = Proto2Response.from_data(data)
+        self.assertEqual(data, resp.error)
+        self.assertEqual(None, resp.result)
+
+    def test_from_data_result(self):
+        resp = Proto2Response.from_data("result")
+        self.assertEqual(None, resp.error)
+        self.assertEqual("result", resp.result)
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -46,17 +46,16 @@ b2g = false
 [test_text_chrome.py]
 disabled = "Bug 896046"
 
 [test_clearing.py]
 [test_typing.py]
 
 [test_log.py]
 [test_emulator.py]
-browser = false
 qemu = true
 
 [test_about_pages.py]
 b2g = false
 
 [test_execute_async_script.py]
 [test_execute_script.py]
 [test_simpletest_fail.js]
--- a/testing/marionette/client/marionette/www/framesetPage2.html
+++ b/testing/marionette/client/marionette/www/framesetPage2.html
@@ -1,7 +1,7 @@
 <html>
 <head></head>
 <frameset cols="*, *">
-    <frame name="child1" src="page/10"/>
-    <frame name="child2" src="page/11"/>
+    <frame name="child1" src="test.html"/>
+    <frame name="child2" src="test.html"/>
 </frameset>
-</html>
\ No newline at end of file
+</html>
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -1618,16 +1618,23 @@ GeckoDriver.prototype.getActiveFrame = f
 
     case Context.CONTENT:
       resp.body.value = this.currentFrameElement;
       break;
   }
 };
 
 /**
+ *
+ */
+GeckoDriver.prototype.switchToParentFrame = function (cmd, resp) {
+  let res = yield this.listener.switchToParentFrame();
+};
+
+/**
  * Switch to a given frame within the current window.
  *
  * @param {Object} element
  *     A web element reference to the element to switch to.
  * @param {(string|number)} id
  *     If element is not defined, then this holds either the id, name,
  *     or index of the frame to switch to.
  */
@@ -2961,16 +2968,17 @@ GeckoDriver.prototype.commands = {
   "getWindowHandles": GeckoDriver.prototype.getWindowHandles,
   "getChromeWindowHandles": GeckoDriver.prototype.getChromeWindowHandles,
   "getCurrentWindowHandles": GeckoDriver.prototype.getWindowHandles,  // Selenium 2 compat
   "getWindows":  GeckoDriver.prototype.getWindowHandles,  // deprecated
   "getWindowPosition": GeckoDriver.prototype.getWindowPosition,
   "setWindowPosition": GeckoDriver.prototype.setWindowPosition,
   "getActiveFrame": GeckoDriver.prototype.getActiveFrame,
   "switchToFrame": GeckoDriver.prototype.switchToFrame,
+  "switchToParentFrame": GeckoDriver.prototype.switchToParentFrame,
   "switchToWindow": GeckoDriver.prototype.switchToWindow,
   "switchToShadowRoot": GeckoDriver.prototype.switchToShadowRoot,
   "deleteSession": GeckoDriver.prototype.deleteSession,
   "importScript": GeckoDriver.prototype.importScript,
   "clearImportedScripts": GeckoDriver.prototype.clearImportedScripts,
   "getAppCacheStatus": GeckoDriver.prototype.getAppCacheStatus,
   "close": GeckoDriver.prototype.close,
   "closeWindow": GeckoDriver.prototype.close,  // deprecated
--- a/testing/marionette/driver/marionette_driver/marionette.py
+++ b/testing/marionette/driver/marionette_driver/marionette.py
@@ -10,26 +10,27 @@ import socket
 import StringIO
 import traceback
 import warnings
 
 from contextlib import contextmanager
 
 from decorators import do_crash_check
 from keys import Keys
-from marionette_transport import MarionetteTransport
+import marionette_transport as transport
 
 from mozrunner import B2GEmulatorRunner
 
 import geckoinstance
 import errors
 
 WEBELEMENT_KEY = "ELEMENT"
 W3C_WEBELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"
 
+
 class HTMLElement(object):
     """
     Represents a DOM Element.
     """
 
     def __init__(self, marionette, id):
         self.marionette = marionette
         assert(id is not None)
@@ -618,26 +619,25 @@ class Marionette(object):
             self.runner = B2GEmulatorRunner(b2g_home=homedir,
                                             logdir=logdir,
                                             process_args=process_args)
             self.emulator = self.runner.device
             self.emulator.connect()
             self.port = self.emulator.setup_port_forwarding(remote_port=self.port)
             assert(self.emulator.wait_for_port(self.port)), "Timed out waiting for port!"
 
-        self.client = MarionetteTransport(
-            self.host,
-            self.port,
-            self.socket_timeout)
-
         if emulator:
             if busybox:
                 self.emulator.install_busybox(busybox=busybox)
             self.emulator.wait_for_system_message(self)
 
+        # for callbacks from a protocol level 2 or lower remote,
+        # we store the callback ID so it can be used by _send_emulator_result
+        self.emulator_callback_id = None
+
     def cleanup(self):
         if self.session:
             try:
                 self.delete_session()
             except (errors.MarionetteException, socket.error, IOError):
                 # These exceptions get thrown if the Marionette server
                 # hit an exception/died or the connection died. We can
                 # do no further server-side cleanup in this case.
@@ -662,116 +662,120 @@ class Marionette(object):
             s.bind((host, port))
             return True
         except socket.error:
             return False
         finally:
             s.close()
 
     def wait_for_port(self, timeout=60):
-        return MarionetteTransport.wait_for_port(self.host,
-                                                 self.port,
-                                                 timeout=timeout)
+        return transport.wait_for_port(self.host, self.port, timeout=timeout)
 
     @do_crash_check
-    def _send_message(self, command, body=None, key=None):
-        if not self.session_id and command != "newSession":
+    def _send_message(self, name, params=None, key=None):
+        if not self.session_id and name != "newSession":
             raise errors.MarionetteException("Please start a session")
 
-        message = {"name": command}
-        if body:
-            message["parameters"] = body
+        try:
+            if self.protocol < 3:
+                data = {"name": name}
+                if params:
+                    data["parameters"] = params
+                self.client.send(data)
+                msg = self.client.receive()
 
-        packet = json.dumps(message)
+            else:
+                msg = self.client.request(name, params)
 
-        try:
-            resp = self.client.send(packet)
         except IOError:
             if self.instance and not hasattr(self.instance, 'detached'):
                 # If we've launched the binary we've connected to, wait
                 # for it to shut down.
                 returncode = self.instance.runner.wait(timeout=self.DEFAULT_STARTUP_TIMEOUT)
                 raise IOError("process died with returncode %s" % returncode)
             raise
         except socket.timeout:
             self.session = None
             self.window = None
             self.client.close()
             raise errors.TimeoutException("Connection timed out")
 
-        # Process any emulator commands that are sent from a script
-        # while it's executing
-        if isinstance(resp, dict) and any (k in resp for k in ("emulator_cmd", "emulator_shell")):
-            while True:
-                id = resp.get("id")
-                cmd = resp.get("emulator_cmd")
-                shell = resp.get("emulator_shell")
-                if cmd:
-                    resp = self._emulator_cmd(id, cmd)
-                    continue
-                if shell:
-                    resp = self._emulator_shell(id, shell)
-                    continue
-                break
+        if isinstance(msg, transport.Command):
+            if msg.name == "runEmulatorCmd":
+                self.emulator_callback_id = msg.params.get("id")
+                msg = self._emulator_cmd(msg.params["emulator_cmd"])
+            elif msg.name == "runEmulatorShell":
+                self.emulator_callback_id = msg.params.get("id")
+                msg = self._emulator_shell(msg.params["emulator_shell"])
+            else:
+                raise IOError("Unknown command: %s" % msg)
 
-        if "error" in resp:
-            self._handle_error(resp)
+        res, err = msg.result, msg.error
+        if err:
+            self._handle_error(err)
 
         if key is not None:
-            return self._unwrap_response(resp.get(key))
+            return self._unwrap_response(res.get(key))
         else:
-            return self._unwrap_response(resp)
+            return self._unwrap_response(res)
 
     def _unwrap_response(self, value):
         if isinstance(value, dict) and \
         (WEBELEMENT_KEY in value or W3C_WEBELEMENT_KEY in value):
             if value.get(WEBELEMENT_KEY):
                 return HTMLElement(self, value.get(WEBELEMENT_KEY))
             else:
                 return HTMLElement(self, value.get(W3C_WEBELEMENT_KEY))
         elif isinstance(value, list):
             return list(self._unwrap_response(item) for item in value)
         else:
             return value
 
-    def _emulator_cmd(self, id, cmd):
+    def _emulator_cmd(self, cmd):
         if not self.emulator:
             raise errors.MarionetteException(
                 "No emulator in this test to run command against")
         payload = cmd.encode("ascii")
         result = self.emulator._run_telnet(payload)
-        return self._send_emulator_result(id, result)
+        return self._send_emulator_result(result)
 
-    def _emulator_shell(self, id, args):
+    def _emulator_shell(self, args):
         if not isinstance(args, list) or not self.emulator:
             raise errors.MarionetteException(
                 "No emulator in this test to run shell command against")
         buf = StringIO.StringIO()
         self.emulator.dm.shell(args, buf)
         result = str(buf.getvalue()[0:-1]).rstrip().splitlines()
         buf.close()
-        return self._send_emulator_result(id, result)
+        return self._send_emulator_result(result)
 
-    def _send_emulator_result(self, id, result):
-        return self.client.send(json.dumps({"name": "emulatorCmdResult",
-                                            "id": id,
-                                            "result": result}))
+    def _send_emulator_result(self, result):
+        if self.protocol < 3:
+            body = {"name": "emulatorCmdResult",
+                    "id": self.emulator_callback_id,
+                    "result": result}
+            self.client.send(body)
+            return self.client.receive()
+        else:
+            return self.client.respond(result)
 
-    def _handle_error(self, resp):
+    def _handle_error(self, obj):
         if self.protocol == 1:
-            if "error" not in resp or not isinstance(resp["error"], dict):
+            if "error" not in obj or not isinstance(obj["error"], dict):
                 raise errors.MarionetteException(
-                    "Malformed packet, expected key 'error' to be a dict: %s" % resp)
-            error = resp["error"].get("status")
-            message = resp["error"].get("message")
-            stacktrace = resp["error"].get("stacktrace")
+                    "Malformed packet, expected key 'error' to be a dict: %s" % obj)
+            error = obj["error"].get("status")
+            message = obj["error"].get("message")
+            stacktrace = obj["error"].get("stacktrace")
+
         else:
-            error = resp["error"]
-            message = resp["message"]
-            stacktrace = resp["stacktrace"]
+            error = obj["error"]
+            message = obj["message"]
+            stacktrace = obj["stacktrace"]
+
         raise errors.lookup(error)(message, stacktrace=stacktrace)
 
     def _reset_timeouts(self):
         if self.timeout is not None:
             self.timeouts(self.TIMEOUT_SEARCH, self.timeout)
             self.timeouts(self.TIMEOUT_SCRIPT, self.timeout)
             self.timeouts(self.TIMEOUT_PAGE, self.timeout)
         else:
@@ -1127,16 +1131,20 @@ class Marionette(object):
 
         :returns: A dict of the capabilities offered."""
         if self.instance:
             returncode = self.instance.runner.process_handler.proc.returncode
             if returncode is not None:
                 # We're managing a binary which has terminated, so restart it.
                 self.instance.restart()
 
+        self.client = transport.TcpTransport(
+            self.host,
+            self.port,
+            self.socket_timeout)
         self.protocol, _ = self.client.connect()
         self.wait_for_port(timeout=timeout)
 
         body = {"capabilities": desired_capabilities, "sessionId": session_id}
         resp = self._send_message("newSession", body)
 
         self.session_id = resp["sessionId"]
         self.session = resp["value"] if self.protocol == 1 else resp["capabilities"]
@@ -1303,17 +1311,16 @@ class Marionette(object):
 
         :param context: Context, may be one of the class properties
             `CONTEXT_CHROME` or `CONTEXT_CONTENT`.
 
         Usage example::
 
             marionette.set_context(marionette.CONTEXT_CHROME)
         """
-        assert(context == self.CONTEXT_CHROME or context == self.CONTEXT_CONTENT)
         if context not in [self.CONTEXT_CHROME, self.CONTEXT_CONTENT]:
             raise ValueError("Unknown context: %s" % context)
         self._send_message("setContext", {"value": context})
 
     @contextmanager
     def using_context(self, context):
         """Sets the context that Marionette commands are running in using
         a `with` statement. The state of the context on the server is
@@ -1363,16 +1370,22 @@ class Marionette(object):
         if element:
             return HTMLElement(self, element)
         return None
 
     def switch_to_default_content(self):
         """Switch the current context to page's default content."""
         return self.switch_to_frame()
 
+    def switch_to_parent_frame(self):
+        """
+           Switch to the Parent Frame
+        """
+        self._send_message("switchToParentFrame")
+
     def switch_to_frame(self, frame=None, focus=True):
         """Switch the current context to the specified frame. Subsequent
         commands will operate in the context of the specified frame,
         if applicable.
 
         :param frame: A reference to the frame to switch to.  This can
             be an ``HTMLElement``, an integer index, string name, or an
             ID attribute.  If you call ``switch_to_frame`` without an
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -250,16 +250,17 @@ function startListeners() {
   addMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
   addMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
   addMessageListenerId("Marionette:getElementRect", getElementRectFn);
   addMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
   addMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
   addMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
   addMessageListenerId("Marionette:clearElement", clearElementFn);
   addMessageListenerId("Marionette:switchToFrame", switchToFrame);
+  addMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
   addMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
   addMessageListenerId("Marionette:deleteSession", deleteSession);
   addMessageListenerId("Marionette:sleepSession", sleepSession);
   addMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
   addMessageListenerId("Marionette:importScript", importScript);
   addMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
   addMessageListenerId("Marionette:setTestName", setTestName);
   addMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
@@ -354,16 +355,17 @@ function deleteSession(msg) {
   removeMessageListenerId("Marionette:isElementDisplayed", isElementDisplayedFn);
   removeMessageListenerId("Marionette:getElementValueOfCssProperty", getElementValueOfCssPropertyFn);
   removeMessageListenerId("Marionette:getElementRect", getElementRectFn);
   removeMessageListenerId("Marionette:isElementEnabled", isElementEnabledFn);
   removeMessageListenerId("Marionette:isElementSelected", isElementSelectedFn);
   removeMessageListenerId("Marionette:sendKeysToElement", sendKeysToElement);
   removeMessageListenerId("Marionette:clearElement", clearElementFn);
   removeMessageListenerId("Marionette:switchToFrame", switchToFrame);
+  removeMessageListenerId("Marionette:switchToParentFrame", switchToParentFrame);
   removeMessageListenerId("Marionette:switchToShadowRoot", switchToShadowRootFn);
   removeMessageListenerId("Marionette:deleteSession", deleteSession);
   removeMessageListenerId("Marionette:sleepSession", sleepSession);
   removeMessageListenerId("Marionette:emulatorCmdResult", emulatorCmdResult);
   removeMessageListenerId("Marionette:importScript", importScript);
   removeMessageListenerId("Marionette:getAppCacheStatus", getAppCacheStatus);
   removeMessageListenerId("Marionette:setTestName", setTestName);
   removeMessageListenerId("Marionette:takeScreenshot", takeScreenshotFn);
@@ -1675,16 +1677,30 @@ function switchToShadowRoot(id) {
   foundShadowRoot = hostEl.shadowRoot;
   if (!foundShadowRoot) {
     throw new NoSuchElementError('Unable to locate shadow root: ' + id);
   }
   curContainer.shadowRoot = foundShadowRoot;
 }
 
 /**
+ * Switch to the parent frame of the current Frame. If the frame is the top most
+ * is the current frame then no action will happen.
+ */
+ function switchToParentFrame(msg) {
+   let command_id = msg.json.command_id;
+   curContainer.frame = curContainer.frame.parent;
+   let parentElement = elementManager.addToKnownElements(curContainer.frame);
+
+   sendSyncMessage("Marionette:switchedToFrame", { frameValue: parentElement });
+
+   sendOk(msg.json.command_id);
+ }
+
+/**
  * Switch to frame given either the server-assigned element id,
  * its index in window.frames, or the iframe's name or id.
  */
 function switchToFrame(msg) {
   let command_id = msg.json.command_id;
   function checkLoad() {
     let errorRegex = /about:.+(error)|(blocked)\?/;
     if (curContainer.frame.document.readyState == "complete") {
--- a/testing/marionette/transport/marionette_transport/__init__.py
+++ b/testing/marionette/transport/marionette_transport/__init__.py
@@ -1,8 +1,7 @@
 # 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/
 
 __version__ = '0.7.1'
 
-
-from transport import MarionetteTransport
+from transport import *
--- a/testing/marionette/transport/marionette_transport/transport.py
+++ b/testing/marionette/transport/marionette_transport/transport.py
@@ -2,136 +2,309 @@
 # 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/.
 
 import datetime
 import errno
 import json
 import socket
 import time
+import types
+
+
+class Message(object):
+    def __init__(self, msgid):
+        self.id = msgid
+
+    def __eq__(self, other):
+        return self.id == other.id
+
+
+class Command(Message):
+    TYPE = 0
+
+    def __init__(self, msgid, name, params):
+        Message.__init__(self, msgid)
+        self.name = name
+        self.params = params
+
+    def __str__(self):
+        return "<Command id=%s, name=%s, params=%s>" % (self.id, self.name, self.params)
+
+    def to_msg(self):
+        msg = [Command.TYPE, self.id, self.name, self.params]
+        return json.dumps(msg)
+
+    @staticmethod
+    def from_msg(payload):
+        data = json.loads(payload)
+        assert data[0] == Command.TYPE
+        cmd = Command(data[1], data[2], data[3])
+        return cmd
 
 
-class MarionetteTransport(object):
-    """The Marionette socket client.  This speaks the same protocol
-    as the remote debugger inside Gecko, in which messages are always
-    preceded by the message length and a colon, e.g.:
+class Response(Message):
+    TYPE = 1
+
+    def __init__(self, msgid, error, result):
+        Message.__init__(self, msgid)
+        self.error = error
+        self.result = result
+
+    def __str__(self):
+        return "<Response id=%s, error=%s, result=%s>" % (self.id, self.error, self.result)
 
-        20:{"command": "test"}
+    def to_msg(self):
+       msg = [Response.TYPE, self.id, self.error, self.result]
+       return json.dumps(msg)
+
+    @staticmethod
+    def from_msg(payload):
+        data = json.loads(payload)
+        assert data[0] == Response.TYPE
+        return Response(data[1], data[2], data[3])
+
+
+class Proto2Command(Command):
+    """Compatibility shim that marshals messages from a protocol level
+    2 and below remote into ``Command`` objects.
     """
 
+    def __init__(self, name, params):
+        Command.__init__(self, None, name, params)
+
+    @staticmethod
+    def from_data(data):
+        if "emulator_cmd" in data:
+            name = "runEmulatorCmd"
+        elif "emulator_shell" in data:
+            name = "runEmulatorShell"
+        else:
+            raise ValueError
+        return Proto2Command(name, data)
+
+
+class Proto2Response(Response):
+    """Compatibility shim that marshals messages from a protocol level
+    2 and below remote into ``Response`` objects.
+    """
+
+    def __init__(self, error, result):
+        Response.__init__(self, None, error, result)
+
+    @staticmethod
+    def from_data(data):
+        err, res = None, None
+        if "error" in data:
+            err = data
+        else:
+            res = data
+        return Proto2Response(err, res)
+
+
+class TcpTransport(object):
+    """Socket client that communciates with Marionette via TCP.
+
+    It speaks the protocol of the remote debugger in Gecko, in which
+    messages are always preceded by the message length and a colon, e.g.:
+
+        7:MESSAGE
+
+    On top of this protocol it uses a Marionette message format, that
+    depending on the protocol level offered by the remote server, varies.
+    Supported protocol levels are 1 and above.
+    """
     max_packet_length = 4096
     connection_lost_msg = "Connection to Marionette server is lost. Check gecko.log (desktop firefox) or logcat (b2g) for errors."
 
     def __init__(self, addr, port, socket_timeout=360.0):
         self.addr = addr
         self.port = port
         self.socket_timeout = socket_timeout
-        self.sock = None
+
         self.protocol = 1
         self.application_type = None
+        self.last_id = 0
+        self.expected_responses = []
+
+        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.sock.settimeout(self.socket_timeout)
 
     def _recv_n_bytes(self, n):
-        """Convenience method for receiving exactly n bytes from self.sock
-        (assuming it's open and connected).
-        """
         data = ""
         while len(data) < n:
             chunk = self.sock.recv(n - len(data))
             if chunk == "":
                 break
             data += chunk
         return data
 
-    def receive(self):
-        """Receive the next complete response from the server, and
-        return it as a JSON structure.  Each response from the server
-        is prepended by len(message) + ":".
+    def _unmarshal(self, packet):
+        msg = None
+
+        # protocol 3 and above
+        if self.protocol >= 3:
+            typ = int(packet[1])
+            if typ == Command.TYPE:
+                msg = Command.from_msg(packet)
+            elif typ == Response.TYPE:
+                msg = Response.from_msg(packet)
+
+        # protocol 2 and below
+        else:
+            data = json.loads(packet)
+
+            # emulator callbacks
+            if isinstance(data, dict) and any(k in data for k in ("emulator_cmd", "emulator_shell")):
+                msg = Proto2Command.from_data(data)
+
+            # everything else
+            else:
+                msg = Proto2Response.from_data(data)
+
+        return msg
+
+    def receive(self, unmarshal=True):
+        """Wait for the next complete response from the remote.
+
+        :param unmarshal: Default is to deserialise the packet and
+            return a ``Message`` type.  Setting this to false will return
+            the raw packet.
         """
-        assert(self.sock)
         now = time.time()
-        response = ''
+        data = ""
         bytes_to_recv = 10
+
         while time.time() - now < self.socket_timeout:
             try:
-                data = self.sock.recv(bytes_to_recv)
-                response += data
+                chunk = self.sock.recv(bytes_to_recv)
+                data += chunk
             except socket.timeout:
                 pass
             else:
-                if not data:
+                if not chunk:
                     raise IOError(self.connection_lost_msg)
-            sep = response.find(':')
+
+            sep = data.find(":")
             if sep > -1:
-                length = response[0:sep]
-                remaining = response[sep + 1:]
+                length = data[0:sep]
+                remaining = data[sep + 1:]
+
                 if len(remaining) == int(length):
-                    return json.loads(remaining)
+                    if unmarshal:
+                        msg = self._unmarshal(remaining)
+                        self.last_id = msg.id
+
+                        if isinstance(msg, Response) and self.protocol >= 3:
+                            if msg not in self.expected_responses:
+                                raise Exception("Received unexpected response: %s" % msg)
+                            else:
+                                self.expected_responses.remove(msg)
+
+                        return msg
+                    else:
+                        return remaining
+
                 bytes_to_recv = int(length) - len(remaining)
-        raise socket.timeout('connection timed out after %d s' % self.socket_timeout)
+
+        raise socket.timeout("connection timed out after %ds" % self.socket_timeout)
 
     def connect(self):
         """Connect to the server and process the hello message we expect
         to receive in response.
 
-        Return a tuple of the protocol level and the application type.
+        Returns a tuple of the protocol level and the application type.
         """
-        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.settimeout(self.socket_timeout)
         try:
             self.sock.connect((self.addr, self.port))
         except:
             # Unset self.sock so that the next attempt to send will cause
             # another connection attempt.
             self.sock = None
             raise
+
         self.sock.settimeout(2.0)
 
-        hello = self.receive()
+        # first packet is always a JSON Object
+        # which we can use to tell which protocol level we are at
+        raw = self.receive(unmarshal=False)
+        hello = json.loads(raw)
         self.protocol = hello.get("marionetteProtocol", 1)
         self.application_type = hello.get("applicationType")
 
         return (self.protocol, self.application_type)
 
-    def send(self, data):
-        """Send a message on the socket, prepending it with len(msg) + ":"."""
+    def send(self, obj):
+        """Send message to the remote server.  Allowed input is a
+        ``Message`` instance or a JSON serialisable object.
+        """
         if not self.sock:
             self.connect()
-        data = "%s:%s" % (len(data), data)
 
-        for packet in [data[i:i + self.max_packet_length] for i in
-                       range(0, len(data), self.max_packet_length)]:
+        if isinstance(obj, Message):
+            data = obj.to_msg()
+            self.expected_responses.append(obj)
+        else:
+            data = json.dumps(obj)
+        payload = "%s:%s" % (len(data), data)
+
+        for packet in [payload[i:i + self.max_packet_length] for i in
+                       range(0, len(payload), self.max_packet_length)]:
             try:
                 self.sock.send(packet)
             except IOError as e:
                 if e.errno == errno.EPIPE:
                     raise IOError("%s: %s" % (str(e), self.connection_lost_msg))
                 else:
                     raise e
 
+    def respond(self, obj):
+        """Send a response to a command.  This can be an arbitrary JSON
+        serialisable object or an ``Exception``.
+        """
+        res, err = None, None
+        if isinstance(obj, Exception):
+            err = obj
+        else:
+            res = obj
+        msg = Response(self.last_id, err, res)
+        self.send(msg)
+        return self.receive()
+
+    def request(self, name, params):
+        """Sends a message to the remote server and waits for a response
+        to come back.
+        """
+        self.last_id = self.last_id + 1
+        cmd = Command(self.last_id, name, params)
+        self.send(cmd)
         return self.receive()
 
     def close(self):
         """Close the socket."""
         if self.sock:
             self.sock.close()
+
+    def __del__(self):
+        self.close()
         self.sock = None
 
-    @staticmethod
-    def wait_for_port(host, port, timeout=60):
-        """ Wait for the specified Marionette host/port to be available."""
-        starttime = datetime.datetime.now()
-        poll_interval = 0.1
-        while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
-            sock = None
-            try:
-                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                sock.connect((host, port))
-                data = sock.recv(16)
+
+def wait_for_port(host, port, timeout=60):
+    """ Wait for the specified host/port to be available."""
+    starttime = datetime.datetime.now()
+    poll_interval = 0.1
+    while datetime.datetime.now() - starttime < datetime.timedelta(seconds=timeout):
+        sock = None
+        try:
+            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+            sock.connect((host, port))
+            data = sock.recv(16)
+            sock.close()
+            if ':' in data:
+                return True
+        except socket.error:
+            pass
+        finally:
+            if sock:
                 sock.close()
-                if ':' in data:
-                    return True
-            except socket.error:
-                pass
-            finally:
-                if sock:
-                    sock.close()
-            time.sleep(poll_interval)
-        return False
+        time.sleep(poll_interval)
+    return False
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/send-content-type-string.htm.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[send-content-type-string.htm]
-  type: testharness
-  [XMLHttpRequest: send() - Content-Type 1]
-    expected: FAIL
-
-  [XMLHttpRequest: send() - Content-Type 2]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/meta/XMLHttpRequest/send-entity-body-document.htm.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[send-entity-body-document.htm]
-  type: testharness
-  [XMLHttpRequest: send() - Document]
-    expected: FAIL
-
-  [XMLHttpRequest: send() - Document 1]
-    expected: FAIL
-
-  [XMLHttpRequest: send() - Document 2]
-    expected: FAIL
-
-  [XMLHttpRequest: send() - Document 3]
-    expected: FAIL
-
-  [XMLHttpRequest: send() - Document 4]
-    expected: FAIL
-
--- a/testing/web-platform/mozilla/meta/MANIFEST.json
+++ b/testing/web-platform/mozilla/meta/MANIFEST.json
@@ -464,22 +464,16 @@
           }
         ],
         "service-workers/service-worker/state.https.html": [
           {
             "path": "service-workers/service-worker/state.https.html",
             "url": "/_mozilla/service-workers/service-worker/state.https.html"
           }
         ],
-        "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html": [
-          {
-            "path": "service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html",
-            "url": "/_mozilla/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html"
-          }
-        ],
         "service-workers/service-worker/synced-state.https.html": [
           {
             "path": "service-workers/service-worker/synced-state.https.html",
             "url": "/_mozilla/service-workers/service-worker/synced-state.https.html"
           }
         ],
         "service-workers/service-worker/uncontrolled-page.https.html": [
           {
@@ -523,18 +517,24 @@
             "url": "/_mozilla/service-workers/service-worker/waiting.https.html"
           }
         ],
         "service-workers/service-worker/worker-interception.https.html": [
           {
             "path": "service-workers/service-worker/worker-interception.https.html",
             "url": "/_mozilla/service-workers/service-worker/worker-interception.https.html"
           }
+        ],
+        "service-workers/service-worker/xhr.https.html": [
+          {
+            "path": "service-workers/service-worker/xhr.https.html",
+            "url": "/_mozilla/service-workers/service-worker/xhr.https.html"
+          }
         ]
       }
     },
     "reftest_nodes": {}
   },
   "reftest_nodes": {},
   "rev": null,
   "url_base": "/_mozilla/",
   "version": 2
-}
\ No newline at end of file
+}
deleted file mode 100644
--- a/testing/web-platform/mozilla/meta/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[sync-xhr-doesnt-deadlock.https.html]
-  type: testharness
-  [Verify SyncXHR does not deadlock]
-    expected: FAIL
-
deleted file mode 100644
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock-iframe.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: SyncXHR doesn't deadlock iframe</title>
-<script>
-function performSyncXHR() {
-  var url = 'sync-xhr-doesnt-deadlock.data?bustcache=' + Date.now();
-  var syncXhr = new XMLHttpRequest();
-  syncXhr.open("GET", url, false);
-  syncXhr.send();
-  if (syncXhr.responseText != 'hello')
-    throw 'FAIL';
-}
-</script>
deleted file mode 100644
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.data
+++ /dev/null
@@ -1,1 +0,0 @@
-hello
\ No newline at end of file
deleted file mode 100644
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/sync-xhr-doesnt-deadlock.js
+++ /dev/null
@@ -1,5 +0,0 @@
-self.onfetch = function(event) {
-  if (event.request.url.indexOf('sync-xhr-doesnt-deadlock.data') == -1)
-    return;
-  event.respondWith(fetch('404resource?bustcache=' + Date.now()));
-};
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/resources/xhr.js
@@ -0,0 +1,6 @@
+self.addEventListener('activate', function(event) {
+    event.waitUntil(clients.claim());
+  });
+self.addEventListener('message', function(event) {
+    event.data.port.postMessage({xhr: !!("XMLHttpRequest" in self)});
+  });
deleted file mode 100644
--- a/testing/web-platform/mozilla/tests/service-workers/service-worker/sync-xhr-doesnt-deadlock.https.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<title>Service Worker: SyncXHR doesn't deadlock</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="resources/test-helpers.sub.js"></script>
-<script>
-
-async_test(function(t) {
-    var url = 'resources/sync-xhr-doesnt-deadlock.js';
-    var scope = 'resources/sync-xhr-doesnt-deadlock-iframe.html';
-
-    service_worker_unregister_and_register(t, url, scope)
-      .then(function(registration) {
-          return wait_for_state(t, registration.installing, 'activated');
-        })
-      .then(function() { return with_iframe(scope); })
-      .then(function(frame) {
-          frame.contentWindow.performSyncXHR();
-          service_worker_unregister_and_done(t, scope);
-        })
-      .catch(unreached_rejection(t));
-  }, 'Verify SyncXHR does not deadlock');
-</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/mozilla/tests/service-workers/service-worker/xhr.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Service Worker: XHR doesn't exist</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js?pipe=sub"></script>
+<script>
+
+async_test(function(t) {
+    var path = new URL(".", window.location).pathname
+    var url = 'resources/xhr.js';
+    var scope = 'resources/blank.html?xhr';
+    var host_info = get_host_info();
+    var frameURL = host_info['HTTPS_ORIGIN'] + path + scope;
+
+    service_worker_unregister_and_register(t, url, scope)
+      .then(function(registration) {
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(function() { return with_iframe(frameURL); })
+      .then(function(frame) {
+        return new Promise(function(resolve, reject) {
+          function onMessage(e) {
+            assert_false(e.data.xhr);
+            service_worker_unregister_and_done(t, scope);
+          }
+          var channel = new MessageChannel();
+          channel.port1.onmessage = t.step_func(onMessage);
+          frame.contentWindow.navigator.serviceWorker.controller.postMessage({port: channel.port2}, [channel.port2]);
+        })
+      })
+      .catch(unreached_rejection(t));
+  }, 'Verify XHR does not exist');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/XMLHttpRequest/resources/empty-div-utf8-html.py
@@ -0,0 +1,5 @@
+def main(request, response):
+    headers = [("Content-type", "text/html;charset=utf-8")]
+    content = "<!DOCTYPE html><div></div>"
+
+    return headers, content
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/XMLHttpRequest/resources/img-utf8-html.py
@@ -0,0 +1,5 @@
+def main(request, response):
+    headers = [("Content-type", "text/html;charset=utf-8")]
+    content = "<img>foo"
+
+    return headers, content
--- a/testing/web-platform/tests/XMLHttpRequest/send-content-type-string.htm
+++ b/testing/web-platform/tests/XMLHttpRequest/send-content-type-string.htm
@@ -15,12 +15,12 @@
           client.open("POST", "resources/content.py", false)
           client.send(data)
           assert_equals(client.getResponseHeader("x-request-content-type"), expected_type)
         })
       }
       request("TEST", "text/plain;charset=UTF-8")
       function init(fr) { request(fr.contentDocument, fr.getAttribute("data-t")) }
     </script>
-    <iframe src='data:text/xml;charset=windows-1252,<%FF/>' onload="init(this)" data-t="application/xml;charset=windows-1252"></iframe>
-    <iframe src='data:text/html;charset=windows-1252,%FF' onload="init(this)" data-t="text/html;charset=windows-1252"></iframe>
+    <iframe src='data:text/xml;charset=windows-1252,<%FF/>' onload="init(this)" data-t="application/xml;charset=UTF-8"></iframe>
+    <iframe src='data:text/html;charset=windows-1252,%FF' onload="init(this)" data-t="text/html;charset=UTF-8"></iframe>
   </body>
 </html>
--- a/testing/web-platform/tests/XMLHttpRequest/send-entity-body-document.htm
+++ b/testing/web-platform/tests/XMLHttpRequest/send-entity-body-document.htm
@@ -11,45 +11,51 @@
   <body>
     <div id="log"></div>
     <script>
      var expectations = [
       { contentType: 'application/xml;charset=UTF-8', responseText : '<\u00FF\/>' },
       { contentType: 'text/html;charset=UTF-8', responseText : '<body>\uFFFD<\/body>' }, /*invalid character code in document turns into FFFD*/
       { contentType: 'text/html;charset=UTF-8', responseText : '<body>\u30C6\u30b9\u30c8<\/body>' } /* correctly serialized Shift-JIS */,
       { contentType: 'text/html;charset=UTF-8', responseText: 'top' }, /* There's some markup included, but it's not really relevant for this test suite, so we do an indexOf() test */
-      { contentType: 'text/html;charset=UTF-8' }
+      { contentType: 'text/html;charset=UTF-8' },
+      { contentType: 'text/html;charset=UTF-8', responseText: '<img>foo' },
+      { contentType: 'text/html;charset=UTF-8', responseText: '<!DOCTYPE html><html><head></head><body><div></div></body></html>' }
      ]
 
 
-      function request(input, isHTML, title) {
+      function request(input, number, title) {
         test(function() {
           var client = new XMLHttpRequest()
           client.open("POST", "resources/content.py?response_charset_label=UTF-8", false)
           client.send(input)
           var exp = expectations[number]
           assert_equals(client.getResponseHeader('X-Request-Content-Type'), exp.contentType, 'document should be serialized and sent as '+exp.contentType+' (TEST#'+number+')')
           // The indexOf() assertation will overlook some stuff, i.e. XML prologues that shouldn't be there (looking at you, Presto).
           // However, arguably these things have little to do with the XHR functionality we're testing.
           if(exp.responseText){ // This test does not want to assert anything about what markup a standalone IMG should be wrapped in. Hence the GIF test lacks a responseText expectation.
-            assert_true(client.responseText.indexOf(exp.responseText) != -1);
+            assert_true(client.responseText.indexOf(exp.responseText) != -1,
+                        JSON.stringify(exp.responseText) + " not in " +
+                        JSON.stringify(client.responseText));
           }
           assert_equals(client.responseXML, null)
         }, title)
       }
-      function init(fr, number, title) { request(fr.contentDocument, number) }
+      function init(fr, number, title) { request(fr.contentDocument, number, title) }
     </script>
     <!--
         This test also tests how documents in various encodings are serialized.
         The below IFRAMEs contain:
           * one XML document parsed from a windows-1252 source - content is <ÿ/>
           * one HTML-document parsed from an invalid UTF-8 source, will contain a basic HTML DOM
              with a U+FFFD replacement character for the invalid char
           * one HTML document parsed from a valid Shift-JIS source
      -->
     <iframe src='resources/win-1252-xml.py' onload="init(this, 0, 'XML document, windows-1252')"></iframe>
     <iframe src='resources/invalid-utf8-html.py' onload="init(this, 1, 'HTML document, invalid UTF-8')"></iframe>
     <iframe src='resources/shift-jis-html.py' onload="init(this, 2, 'HTML document, shift-jis')"></iframe>
     <iframe src='folder.txt' onload="init(this, 3, 'plain text file')"></iframe>
     <iframe src='resources/image.gif' onload="init(this, 4, 'image file')"></iframe>
+    <iframe src='resources/img-utf8-html.py' onload="init(this, 5, 'img tag')"></iframe>
+    <iframe src='resources/empty-div-utf8-html.py' onload="init(this, 6, 'empty div')"></iframe>
 
   </body>
 </html>
--- a/toolkit/modules/SelectContentHelper.jsm
+++ b/toolkit/modules/SelectContentHelper.jsm
@@ -105,16 +105,17 @@ function buildOptionListForChildren(node
       if (textContent == null) {
         textContent = "";
       }
 
       let info = {
         tagName: tagName,
         textContent: textContent,
         disabled: child.disabled,
+        display: child.style.display,
         // We need to do this for every option element as each one can have
         // an individual style set for direction
         textDirection: getComputedDirection(child),
         tooltip: child.title,
         // XXX this uses a highlight color when this is the selected element.
         // We need to suppress such highlighting in the content process to get
         // the option's correct unhighlighted color here.
         // We also need to detect default color vs. custom so that a standard
--- a/toolkit/modules/SelectParentHelper.jsm
+++ b/toolkit/modules/SelectParentHelper.jsm
@@ -81,16 +81,17 @@ function populateChildren(menulist, opti
 
   for (let option of options) {
     let isOptGroup = (option.tagName == 'OPTGROUP');
     let item = element.ownerDocument.createElement(isOptGroup ? "menucaption" : "menuitem");
 
     item.setAttribute("label", option.textContent);
     item.style.direction = option.textDirection;
     item.style.fontSize = adjustedTextSize;
+    item.style.display = option.display;
     item.setAttribute("tooltiptext", option.tooltip);
 
     element.appendChild(item);
 
     // A disabled optgroup disables all of its child options.
     let isDisabled = isGroupDisabled || option.disabled;
     if (isDisabled) {
       item.setAttribute("disabled", "true");
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -345,16 +345,18 @@ XRE_InitChildProcess(int aArgc,
     if (_fileno(stdin) == -1 || _get_osfhandle(fileno(stdin)) == -1)
         freopen("CONIN$", "r", stdin);
   }
 #endif
 
   // NB: This must be called before profiler_init
   NS_LogInit();
 
+  mozilla::LogModule::Init();
+
   char aLocal;
   profiler_init(&aLocal);
 
   PROFILER_LABEL("Startup", "XRE_InitChildProcess",
     js::ProfileEntry::Category::OTHER);
 
   // Complete 'task_t' exchange for Mac OS X. This structure has the same size
   // regardless of architecture so we don't have any cross-arch issues here.
new file mode 100644
--- /dev/null
+++ b/xpcom/base/Logging.cpp
@@ -0,0 +1,100 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/Logging.h"
+
+#include <algorithm>
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/StaticPtr.h"
+#include "nsClassHashtable.h"
+
+// NB: Initial amount determined by auditing the codebase for the total amount
+//     of unique module names and padding up to the next power of 2.
+const uint32_t kInitialModuleCount = 256;
+
+namespace mozilla {
+/**
+ * Safely converts an integer into a valid LogLevel.
+ */
+LogLevel
+Clamp(int32_t aLevel)
+{
+  aLevel = std::min(aLevel, static_cast<int32_t>(LogLevel::Verbose));
+  aLevel = std::max(aLevel, static_cast<int32_t>(LogLevel::Disabled));
+  return static_cast<LogLevel>(aLevel);
+}
+
+class LogModuleManager
+{
+public:
+  LogModuleManager()
+    : mModulesLock("logmodules")
+    , mModules(kInitialModuleCount)
+  {
+  }
+
+  ~LogModuleManager()
+  {
+    // NB: mModules owns all of the log modules, they will get destroyed by
+    //     its destructor.
+  }
+
+  LogModule* CreateOrGetModule(const char* aName)
+  {
+    OffTheBooksMutexAutoLock guard(mModulesLock);
+    LogModule* module = nullptr;
+    if (!mModules.Get(aName, &module)) {
+      // Create the PRLogModule, this will read any env vars that set the log
+      // level ahead of time. The module is held internally by NSPR, so it's
+      // okay to drop the pointer when leaving this scope.
+      PRLogModuleInfo* prModule = PR_NewLogModule(aName);
+
+      // NSPR does not impose a restriction on the values that log levels can
+      // be. LogModule uses the LogLevel enum class so we must clamp the value
+      // to a max of Verbose.
+      LogLevel logLevel = Clamp(prModule->level);
+      module = new LogModule(logLevel);
+      mModules.Put(aName, module);
+    }
+
+    return module;
+  }
+
+private:
+  OffTheBooksMutex mModulesLock;
+  nsClassHashtable<nsCharPtrHashKey, LogModule> mModules;
+};
+
+StaticAutoPtr<LogModuleManager> sLogModuleManager;
+
+LogModule*
+LogModule::Get(const char* aName)
+{
+  // This is just a pass through to the LogModuleManager so
+  // that the LogModuleManager implementation can be kept internal.
+  MOZ_ASSERT(sLogModuleManager != nullptr);
+  return sLogModuleManager->CreateOrGetModule(aName);
+}
+
+void
+LogModule::Init()
+{
+  // NB: This method is not threadsafe; it is expected to be called very early
+  //     in startup prior to any other threads being run.
+  if (sLogModuleManager) {
+    // Already initialized.
+    return;
+  }
+
+  // NB: We intentionally do not register for ClearOnShutdown as that happens
+  //     before all logging is complete. And, yes, that means we leak, but
+  //     we're doing that intentionally.
+  sLogModuleManager = new LogModuleManager();
+}
+
+} // namespace mozilla
rename from xpcom/glue/Logging.h
rename to xpcom/base/Logging.h
--- a/xpcom/glue/Logging.h
+++ b/xpcom/base/Logging.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_logging_h
 #define mozilla_logging_h
 
 #include "prlog.h"
 
 #include "mozilla/Assertions.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Likely.h"
 
 // This file is a placeholder for a replacement to the NSPR logging framework
 // that is defined in prlog.h. Currently it is just a pass through, but as
 // work progresses more functionality will be swapped out in favor of
 // mozilla logging implementations.
 
 namespace mozilla {
 
@@ -38,23 +40,109 @@ enum class LogLevel {
   Disabled = 0,
   Error,
   Warning,
   Info,
   Debug,
   Verbose,
 };
 
+class LogModule
+{
+public:
+  /**
+   * Retrieves the module with the given name. If it does not already exist
+   * it will be created.
+   *
+   * @param aName The name of the module.
+   * @return A log module for the given name. This may be shared.
+   */
+#if !defined(MOZILLA_XPCOMRT_API)
+  static LogModule* Get(const char* aName);
+#else
+  // For simplicity, libxpcomrt doesn't supoort logging.
+  static LogModule* Get(const char* aName) { return nullptr; }
+#endif
+
+  static void Init();
+
+  /**
+   * Indicates whether or not the given log level is enabled.
+   */
+  bool ShouldLog(LogLevel aLevel) const { return mLevel >= aLevel; }
+
+  /**
+   * Retrieves the log module's current level.
+   */
+  LogLevel Level() const { return mLevel; }
+
+private:
+  friend class LogModuleManager;
+
+  explicit LogModule(LogLevel aLevel) : mLevel(aLevel) {}
+
+  LogModule(LogModule&) = delete;
+  LogModule& operator=(const LogModule&) = delete;
+
+  Atomic<LogLevel, Relaxed> mLevel;
+};
+
+/**
+ * Helper class that lazy loads the given log module. This is safe to use for
+ * declaring static references to log modules and can be used as a replacement
+ * for accessing a LogModule directly.
+ *
+ * Example usage:
+ *   static LazyLogModule sLayoutLog("layout");
+ *
+ *   void Foo() {
+ *     MOZ_LOG(sLayoutLog, LogLevel::Verbose, ("Entering foo"));
+ *   }
+ */
+class LazyLogModule final
+{
+public:
+  explicit MOZ_CONSTEXPR LazyLogModule(const char* aLogName)
+    : mLogName(aLogName)
+    , mLog(nullptr)
+  {
+  }
+
+  operator LogModule*()
+  {
+    // NB: The use of an atomic makes the reading and assignment of mLog
+    //     thread-safe. There is a small chance that mLog will be set more
+    //     than once, but that's okay as it will be set to the same LogModule
+    //     instance each time. Also note LogModule::Get is thread-safe.
+    LogModule* tmp = mLog;
+    if (MOZ_UNLIKELY(!tmp)) {
+      tmp = LogModule::Get(mLogName);
+      mLog = tmp;
+    }
+
+    return tmp;
+  }
+
+private:
+  const char* const mLogName;
+  Atomic<LogModule*, ReleaseAcquire> mLog;
+};
+
 namespace detail {
 
 inline bool log_test(const PRLogModuleInfo* module, LogLevel level) {
   MOZ_ASSERT(level != LogLevel::Disabled);
   return module && module->level >= static_cast<int>(level);
 }
 
+inline bool log_test(const LogModule* module, LogLevel level) {
+  MOZ_ASSERT(level != LogLevel::Disabled);
+  return module && module->ShouldLog(level);
+}
+
 } // namespace detail
 
 } // namespace mozilla
 
 #define MOZ_LOG_TEST(_module,_level) mozilla::detail::log_test(_module, _level)
 
 #define MOZ_LOG(_module,_level,_args)     \
   PR_BEGIN_MACRO             \
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -78,16 +78,17 @@ EXPORTS.mozilla += [
     'CycleCollectedJSRuntime.h',
     'Debug.h',
     'DebuggerOnGCRunnable.h',
     'DeferredFinalize.h',
     'ErrorNames.h',
     'HoldDropJSObjects.h',
     'JSObjectHolder.h',
     'LinuxUtils.h',
+    'Logging.h',
     'nsMemoryInfoDumper.h',
     'OwningNonNull.h',
     'StaticMutex.h',
     'StaticPtr.h',
     'SystemMemoryReporter.h',
 ]
 
 # nsDebugImpl isn't unified because we disable PGO so that NS_ABORT_OOM isn't
@@ -102,16 +103,17 @@ UNIFIED_SOURCES += [
     'ClearOnShutdown.cpp',
     'CycleCollectedJSRuntime.cpp',
     'Debug.cpp',
     'DebuggerOnGCRunnable.cpp',
     'DeferredFinalize.cpp',
     'ErrorNames.cpp',
     'HoldDropJSObjects.cpp',
     'JSObjectHolder.cpp',
+    'Logging.cpp',
     'nsConsoleMessage.cpp',
     'nsConsoleService.cpp',
     'nsCycleCollector.cpp',
     'nsDumpUtils.cpp',
     'nsErrorService.cpp',
     'nsGZFileWriter.cpp',
     'nsInterfaceRequestorAgg.cpp',
     'nsMemoryImpl.cpp',
--- a/xpcom/base/nsDebugImpl.cpp
+++ b/xpcom/base/nsDebugImpl.cpp
@@ -12,17 +12,16 @@
 #include "nsDebugImpl.h"
 #include "nsDebug.h"
 #ifdef MOZ_CRASHREPORTER
 # include "nsExceptionHandler.h"
 #endif
 #include "nsString.h"
 #include "nsXULAppAPI.h"
 #include "prprf.h"
-#include "mozilla/Logging.h"
 #include "nsError.h"
 #include "prerror.h"
 #include "prerr.h"
 #include "prenv.h"
 
 #ifdef ANDROID
 #include <android/log.h>
 #endif
@@ -212,26 +211,16 @@ nsDebugImpl::SetMultiprocessMode(const c
   sMultiprocessDescription = aDesc;
 }
 
 /**
  * Implementation of the nsDebug methods. Note that this code is
  * always compiled in, in case some other module that uses it is
  * compiled with debugging even if this library is not.
  */
-static PRLogModuleInfo* gDebugLog;
-
-static void
-InitLog()
-{
-  if (0 == gDebugLog) {
-    gDebugLog = PR_NewLogModule("nsDebug");
-  }
-}
-
 enum nsAssertBehavior
 {
   NS_ASSERT_UNINITIALIZED,
   NS_ASSERT_WARN,
   NS_ASSERT_SUSPEND,
   NS_ASSERT_STACK,
   NS_ASSERT_TRAP,
   NS_ASSERT_ABORT,
@@ -312,36 +301,30 @@ StuffFixedBuffer(void* aClosure, const c
 
   return aLen;
 }
 
 EXPORT_XPCOM_API(void)
 NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr,
               const char* aFile, int32_t aLine)
 {
-  InitLog();
-
   FixedBuffer buf;
-  mozilla::LogLevel ll = LogLevel::Warning;
   const char* sevString = "WARNING";
 
   switch (aSeverity) {
     case NS_DEBUG_ASSERTION:
       sevString = "###!!! ASSERTION";
-      ll = LogLevel::Error;
       break;
 
     case NS_DEBUG_BREAK:
       sevString = "###!!! BREAK";
-      ll = LogLevel::Error;
       break;
 
     case NS_DEBUG_ABORT:
       sevString = "###!!! ABORT";
-      ll = LogLevel::Error;
       break;
 
     default:
       aSeverity = NS_DEBUG_WARNING;
   };
 
 #  define PrintToBuffer(...) PR_sxprintf(StuffFixedBuffer, &buf, __VA_ARGS__)
 
@@ -366,23 +349,19 @@ NS_DebugBreak(uint32_t aSeverity, const 
     PrintToBuffer("file %s, ", aFile);
   }
   if (aLine != -1) {
     PrintToBuffer("line %d", aLine);
   }
 
 #  undef PrintToBuffer
 
-  // Write out the message to the debug log
-  MOZ_LOG(gDebugLog, ll, ("%s", buf.buffer));
-  PR_LogFlush();
-
   // errors on platforms without a debugdlg ring a bell on stderr
 #if !defined(XP_WIN)
-  if (ll != LogLevel::Warning) {
+  if (aSeverity != NS_DEBUG_WARNING) {
     fprintf(stderr, "\07");
   }
 #endif
 
 #ifdef ANDROID
   __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", buf.buffer);
 #endif
 
--- a/xpcom/build/XPCOMInit.cpp
+++ b/xpcom/build/XPCOMInit.cpp
@@ -493,16 +493,18 @@ NS_InitXPCOM2(nsIServiceManager** aResul
   }
 
   sInitialized = true;
 
   mozPoisonValueInit();
 
   NS_LogInit();
 
+  mozilla::LogModule::Init();
+
   JS_SetCurrentEmbedderTimeFunction(TimeSinceProcessCreation);
 
   char aLocal;
   profiler_init(&aLocal);
   nsresult rv = NS_OK;
 
   // We are not shutting down
   gXPCOMShuttingDown = false;
--- a/xpcom/build/perfprobe.cpp
+++ b/xpcom/build/perfprobe.cpp
@@ -13,26 +13,18 @@
 
 #include "perfprobe.h"
 #include "nsAutoPtr.h"
 
 namespace mozilla {
 namespace probes {
 
 #if defined(MOZ_LOGGING)
-static PRLogModuleInfo*
-GetProbeLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("SysProbe");
-  }
-  return sLog;
-}
-#define LOG(x)  MOZ_LOG(GetProbeLog(), mozilla::LogLevel::Debug, x)
+static LazyLogModule sProbeLog("SysProbe");
+#define LOG(x) MOZ_LOG(sProbeLog, mozilla::LogLevel::Debug, x)
 #else
 #define LOG(x)
 #endif
 
 // Utility function
 GUID
 CID_to_GUID(const nsCID& aCID)
 {
--- a/xpcom/components/nsComponentManager.cpp
+++ b/xpcom/components/nsComponentManager.cpp
@@ -76,17 +76,17 @@
 #include <new>     // for placement new
 
 #include "mozilla/Omnijar.h"
 
 #include "mozilla/Logging.h"
 
 using namespace mozilla;
 
-PRLogModuleInfo* nsComponentManagerLog = nullptr;
+static LazyLogModule nsComponentManagerLog("nsComponentManager");
 
 #if 0 || defined (DEBUG_timeless)
  #define SHOW_DENIED_ON_SHUTDOWN
  #define SHOW_CI_ON_EXISTING_SERVICE
 #endif
 
 // Bloated registry buffer size to improve startup performance -- needs to
 // be big enough to fit the entire file into memory or it'll thrash.
@@ -364,20 +364,16 @@ nsComponentManagerImpl::InitializeModule
   sModuleLocations = new nsTArray<ComponentLocation>;
 }
 
 nsresult
 nsComponentManagerImpl::Init()
 {
   PR_ASSERT(NOT_INITIALIZED == mStatus);
 
-  if (!nsComponentManagerLog) {
-    nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
-  }
-
   // Initialize our arena
   PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
 
 #if !defined(MOZILLA_XPCOMRT_API)
   nsCOMPtr<nsIFile> greDir =
     GetLocationFromDirectoryService(NS_GRE_DIR);
   nsCOMPtr<nsIFile> appDir =
     GetLocationFromDirectoryService(NS_XPCOM_CURRENT_PROCESS_DIR);
--- a/xpcom/components/nsNativeModuleLoader.cpp
+++ b/xpcom/components/nsNativeModuleLoader.cpp
@@ -44,27 +44,18 @@
 #endif
 
 #ifdef DEBUG
 #define IMPLEMENT_BREAK_AFTER_LOAD
 #endif
 
 using namespace mozilla;
 
-static PRLogModuleInfo*
-GetNativeModuleLoaderLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsNativeModuleLoader");
-  }
-  return sLog;
-}
-
-#define LOG(level, args) MOZ_LOG(GetNativeModuleLoaderLog(), level, args)
+static LazyLogModule sNativeModuleLoaderLog("nsNativeModuleLoader");
+#define LOG(level, args) MOZ_LOG(sNativeModuleLoaderLog, level, args)
 
 nsresult
 nsNativeModuleLoader::Init()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Startup not on main thread?");
   LOG(LogLevel::Debug, ("nsNativeModuleLoader::Init()"));
   return NS_OK;
 }
@@ -197,17 +188,17 @@ nsNativeModuleLoader::UnloadLibraries()
   MOZ_ASSERT(NS_IsMainThread(), "Shutdown not on main thread?");
 
   for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) {
     NativeLoadData& loadData = iter.Data();
     loadData.mModule = nullptr;
   }
 
   for (auto iter = mLibraries.Iter(); !iter.Done(); iter.Next()) {
-    if (MOZ_LOG_TEST(GetNativeModuleLoaderLog(), LogLevel::Debug)) {
+    if (MOZ_LOG_TEST(sNativeModuleLoaderLog, LogLevel::Debug)) {
       nsIHashable* hashedFile = iter.Key();
       nsCOMPtr<nsIFile> file(do_QueryInterface(hashedFile));
 
       nsAutoCString filePath;
       file->GetNativePath(filePath);
 
       LOG(LogLevel::Debug,
           ("nsNativeModuleLoader::UnloaderFunc(\"%s\")", filePath.get()));
--- a/xpcom/ds/nsObserverService.cpp
+++ b/xpcom/ds/nsObserverService.cpp
@@ -25,26 +25,18 @@
 //
 // To enable logging (see prlog.h for full details):
 //
 //    set NSPR_LOG_MODULES=ObserverService:5
 //    set NSPR_LOG_FILE=nspr.log
 //
 // this enables LogLevel::Debug level information and places all output in
 // the file nspr.log
-static PRLogModuleInfo*
-GetObserverServiceLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("ObserverService");
-  }
-  return sLog;
-}
-#define LOG(x)  MOZ_LOG(GetObserverServiceLog(), mozilla::LogLevel::Debug, x)
+static mozilla::LazyLogModule sObserverServiceLog("ObserverService");
+#define LOG(x) MOZ_LOG(sObserverServiceLog, mozilla::LogLevel::Debug, x)
 
 using namespace mozilla;
 
 NS_IMETHODIMP
 nsObserverService::CollectReports(nsIHandleReportCallback* aHandleReport,
                                   nsISupports* aData, bool aAnonymize)
 {
   struct SuspectObserver
--- a/xpcom/glue/moz.build
+++ b/xpcom/glue/moz.build
@@ -70,17 +70,16 @@ EXPORTS.mozilla += [
     'AutoRestore.h',
     'BlockingResourceBase.h',
     'CondVar.h',
     'DeadlockDetector.h',
     'EnumeratedArrayCycleCollection.h',
     'FileUtils.h',
     'GenericFactory.h',
     'IntentionalCrash.h',
-    'Logging.h',
     'Monitor.h',
     'Mutex.h',
     'Observer.h',
     'ReentrantMonitor.h',
 ]
 
 include('objs.mozbuild')
 
--- a/xpcom/io/nsInputStreamTee.cpp
+++ b/xpcom/io/nsInputStreamTee.cpp
@@ -17,26 +17,19 @@
 #include "nsIEventTarget.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 
 #ifdef LOG
 #undef LOG
 #endif
-static PRLogModuleInfo*
-GetTeeLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsInputStreamTee");
-  }
-  return sLog;
-}
-#define LOG(args) MOZ_LOG(GetTeeLog(), mozilla::LogLevel::Debug, args)
+
+static LazyLogModule sTeeLog("nsInputStreamTee");
+#define LOG(args) MOZ_LOG(sTeeLog, mozilla::LogLevel::Debug, args)
 
 class nsInputStreamTee final : public nsIInputStreamTee
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIINPUTSTREAM
   NS_DECL_NSIINPUTSTREAMTEE
 
--- a/xpcom/io/nsPipe3.cpp
+++ b/xpcom/io/nsPipe3.cpp
@@ -26,26 +26,18 @@
 using namespace mozilla;
 
 #ifdef LOG
 #undef LOG
 #endif
 //
 // set NSPR_LOG_MODULES=nsPipe:5
 //
-static PRLogModuleInfo*
-GetPipeLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsPipe");
-  }
-  return sLog;
-}
-#define LOG(args) MOZ_LOG(GetPipeLog(), mozilla::LogLevel::Debug, args)
+static LazyLogModule sPipeLog("nsPipe");
+#define LOG(args) MOZ_LOG(sPipeLog, mozilla::LogLevel::Debug, args)
 
 #define DEFAULT_SEGMENT_SIZE  4096
 #define DEFAULT_SEGMENT_COUNT 16
 
 class nsPipe;
 class nsPipeEvents;
 class nsPipeInputStream;
 class nsPipeOutputStream;
--- a/xpcom/io/nsStorageStream.cpp
+++ b/xpcom/io/nsStorageStream.cpp
@@ -36,29 +36,21 @@ using mozilla::ipc::StringInputStreamPar
 // To enable logging (see prlog.h for full details):
 //
 //    set NSPR_LOG_MODULES=StorageStreamLog:5
 //    set NSPR_LOG_FILE=nspr.log
 //
 // this enables LogLevel::Debug level information and places all output in
 // the file nspr.log
 //
-static PRLogModuleInfo*
-GetStorageStreamLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsStorageStream");
-  }
-  return sLog;
-}
+static LazyLogModule sStorageStreamLog("nsStorageStream");
 #ifdef LOG
 #undef LOG
 #endif
-#define LOG(args) MOZ_LOG(GetStorageStreamLog(), mozilla::LogLevel::Debug, args)
+#define LOG(args) MOZ_LOG(sStorageStreamLog, mozilla::LogLevel::Debug, args)
 
 nsStorageStream::nsStorageStream()
   : mSegmentedBuffer(0), mSegmentSize(0), mWriteInProgress(false),
     mLastSegmentNum(-1), mWriteCursor(0), mSegmentEnd(0), mLogicalLength(0)
 {
   LOG(("Creating nsStorageStream [%p].\n", this));
 }
 
--- a/xpcom/threads/AbstractThread.cpp
+++ b/xpcom/threads/AbstractThread.cpp
@@ -17,16 +17,19 @@
 
 #include "nsThreadUtils.h"
 #include "nsContentUtils.h"
 #include "nsServiceManagerUtils.h"
 
 
 namespace mozilla {
 
+LazyLogModule gMozPromiseLog("MozPromise");
+LazyLogModule gStateWatchingLog("StateWatching");
+
 StaticRefPtr<AbstractThread> sMainThread;
 ThreadLocal<AbstractThread*> AbstractThread::sCurrentThreadTLS;
 
 class XPCOMThreadWrapper : public AbstractThread
 {
 public:
   explicit XPCOMThreadWrapper(nsIThread* aTarget, bool aRequireTailDispatch)
     : AbstractThread(aRequireTailDispatch)
@@ -112,19 +115,16 @@ AbstractThread::MainThread()
 {
   MOZ_ASSERT(sMainThread);
   return sMainThread;
 }
 
 void
 AbstractThread::InitStatics()
 {
-  gMozPromiseLog = PR_NewLogModule("MozPromise");
-  gStateWatchingLog = PR_NewLogModule("StateWatching");
-
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!sMainThread);
   nsCOMPtr<nsIThread> mainThread;
   NS_GetMainThread(getter_AddRefs(mainThread));
   MOZ_DIAGNOSTIC_ASSERT(mainThread);
   sMainThread = new XPCOMThreadWrapper(mainThread.get(), /* aRequireTailDispatch = */ true);
   ClearOnShutdown(&sMainThread);
 
--- a/xpcom/threads/MozPromise.h
+++ b/xpcom/threads/MozPromise.h
@@ -15,20 +15,19 @@
 #include "mozilla/Monitor.h"
 #include "mozilla/Tuple.h"
 
 #include "nsTArray.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 
-extern PRLogModuleInfo* gMozPromiseLog;
+extern LazyLogModule gMozPromiseLog;
 
 #define PROMISE_LOG(x, ...) \
-  MOZ_ASSERT(gMozPromiseLog); \
   MOZ_LOG(gMozPromiseLog, mozilla::LogLevel::Debug, (x, ##__VA_ARGS__))
 
 namespace detail {
 template<typename ThisType, typename Ret, typename ArgType>
 static TrueType TakesArgumentHelper(Ret (ThisType::*)(ArgType));
 template<typename ThisType, typename Ret, typename ArgType>
 static TrueType TakesArgumentHelper(Ret (ThisType::*)(ArgType) const);
 template<typename ThisType, typename Ret>
--- a/xpcom/threads/StateWatching.h
+++ b/xpcom/threads/StateWatching.h
@@ -51,20 +51,19 @@
  * and watch the mirrored value.
  *
  * Given that semantics may change and comments tend to go out of date, we
  * deliberately don't provide usage examples here. Grep around to find them.
  */
 
 namespace mozilla {
 
-extern PRLogModuleInfo* gStateWatchingLog;
+extern LazyLogModule gStateWatchingLog;
 
 #define WATCH_LOG(x, ...) \
-  MOZ_ASSERT(gStateWatchingLog); \
   MOZ_LOG(gStateWatchingLog, LogLevel::Debug, (x, ##__VA_ARGS__))
 
 /*
  * AbstractWatcher is a superclass from which all watchers must inherit.
  */
 class AbstractWatcher
 {
 public:
--- a/xpcom/threads/nsEventQueue.cpp
+++ b/xpcom/threads/nsEventQueue.cpp
@@ -8,29 +8,21 @@
 #include "nsAutoPtr.h"
 #include "mozilla/Logging.h"
 #include "nsThreadUtils.h"
 #include "prthread.h"
 #include "mozilla/ChaosMode.h"
 
 using namespace mozilla;
 
-static PRLogModuleInfo*
-GetLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsEventQueue");
-  }
-  return sLog;
-}
+static LazyLogModule sEventQueueLog("nsEventQueue");
 #ifdef LOG
 #undef LOG
 #endif
-#define LOG(args) MOZ_LOG(GetLog(), mozilla::LogLevel::Debug, args)
+#define LOG(args) MOZ_LOG(sEventQueueLog, mozilla::LogLevel::Debug, args)
 
 nsEventQueue::nsEventQueue(Mutex& aLock)
   : mHead(nullptr)
   , mTail(nullptr)
   , mOffsetHead(0)
   , mOffsetTail(0)
   , mEventsAvailable(aLock, "[nsEventQueue.mEventsAvailable]")
 {
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -81,29 +81,21 @@
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #include "TracedTaskCommon.h"
 using namespace mozilla::tasktracer;
 #endif
 
 using namespace mozilla;
 
-static PRLogModuleInfo*
-GetThreadLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsThread");
-  }
-  return sLog;
-}
+static LazyLogModule sThreadLog("nsThread");
 #ifdef LOG
 #undef LOG
 #endif
-#define LOG(args) MOZ_LOG(GetThreadLog(), mozilla::LogLevel::Debug, args)
+#define LOG(args) MOZ_LOG(sThreadLog, mozilla::LogLevel::Debug, args)
 
 NS_DECL_CI_INTERFACE_GETTER(nsThread)
 
 //-----------------------------------------------------------------------------
 // Because we do not have our own nsIFactory, we have to implement nsIClassInfo
 // somewhat manually.
 
 class nsThreadClassInfo : public nsIClassInfo
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -11,29 +11,21 @@
 #include "nsMemory.h"
 #include "nsAutoPtr.h"
 #include "prinrval.h"
 #include "mozilla/Logging.h"
 #include "nsThreadSyncDispatch.h"
 
 using namespace mozilla;
 
-static PRLogModuleInfo*
-GetThreadPoolLog()
-{
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsThreadPool");
-  }
-  return sLog;
-}
+static LazyLogModule sThreadPoolLog("nsThreadPool");
 #ifdef LOG
 #undef LOG
 #endif
-#define LOG(args) MOZ_LOG(GetThreadPoolLog(), mozilla::LogLevel::Debug, args)
+#define LOG(args) MOZ_LOG(sThreadPoolLog, mozilla::LogLevel::Debug, args)
 
 // DESIGN:
 //  o  Allocate anonymous threads.
 //  o  Use nsThreadPool::Run as the main routine for each thread.
 //  o  Each thread waits on the event queue's monitor, checking for
 //     pending events and rescheduling itself as an idle thread.
 
 #define DEFAULT_THREAD_LIMIT 4
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -35,24 +35,22 @@ using mozilla::Atomic;
 using mozilla::LogLevel;
 using mozilla::TimeDuration;
 using mozilla::TimeStamp;
 
 static Atomic<int32_t>  gGenerator;
 static TimerThread*     gThread = nullptr;
 
 // This module prints info about the precision of timers.
-PRLogModuleInfo*
+static mozilla::LazyLogModule sTimerLog("nsTimerImpl");
+
+mozilla::LogModule*
 GetTimerLog()
 {
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("nsTimerImpl");
-  }
-  return sLog;
+  return sTimerLog;
 }
 
 // This module prints info about which timers are firing, which is useful for
 // wakeups for the purposes of power profiling. Set the following environment
 // variable before starting the browser.
 //
 //   NSPR_LOG_MODULES=TimerFirings:4
 //
@@ -78,24 +76,22 @@ GetTimerLog()
 //   cat out | grep timer | sort | uniq -c | sort -r -n
 //
 // This will show how often each unique line appears, with the most common ones
 // first.
 //
 // More detailed docs are here:
 // https://developer.mozilla.org/en-US/docs/Mozilla/Performance/TimerFirings_logging
 //
-PRLogModuleInfo*
+static mozilla::LazyLogModule sTimerFiringsLog("TimerFirings");
+
+mozilla::LogModule*
 GetTimerFiringsLog()
 {
-  static PRLogModuleInfo* sLog;
-  if (!sLog) {
-    sLog = PR_NewLogModule("TimerFirings");
-  }
-  return sLog;
+  return sTimerFiringsLog;
 }
 
 #include <math.h>
 
 double nsTimerImpl::sDeltaSumSquared = 0;
 double nsTimerImpl::sDeltaSum = 0;
 double nsTimerImpl::sDeltaNum = 0;
 
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -17,17 +17,17 @@
 #include "mozilla/Logging.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Variant.h"
 
 #ifdef MOZ_TASK_TRACER
 #include "TracedTaskCommon.h"
 #endif
 
-extern PRLogModuleInfo* GetTimerLog();
+extern mozilla::LogModule* GetTimerLog();
 
 #define NS_TIMER_CID \
 { /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */         \
      0x5ff24248,                                     \
      0x1dd2,                                         \
      0x11b2,                                         \
     {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
 }