merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Mon, 08 Jun 2015 11:55:30 +0200
changeset 247584 4700d1cdf489a05844f3ec5b66c550da40c7cb1f
parent 247583 92926c0d8c8af1ae1ed795576642a95da56efb3b (current diff)
parent 247526 edaec128d6ecec869a03fafd3390cd493eb254c5 (diff)
child 247585 9ef529a9a02b54375bf4a025612201508629a48f
child 247670 64d4c71b2def2e75a9a7d6e0cefd561664d0d5fe
child 247691 7011b4d65de3ff7800574b66ea1708c34022e5bc
child 247709 5507b3f15d4ca69bb25a98adbd38e68befe03989
push id60743
push usercbook@mozilla.com
push dateMon, 08 Jun 2015 10:03:01 +0000
treeherdermozilla-inbound@9ef529a9a02b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
4700d1cdf489 / 41.0a1 / 20150608030201 / files
nightly linux64
4700d1cdf489 / 41.0a1 / 20150608030201 / files
nightly mac
4700d1cdf489 / 41.0a1 / 20150608030201 / files
nightly win32
4700d1cdf489 / 41.0a1 / 20150608030201 / files
nightly win64
4700d1cdf489 / 41.0a1 / 20150608030201 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge mozilla-inbound to mozilla-central a=merge
ipc/chromium/src/base/third_party/purify/pure.h
ipc/chromium/src/base/third_party/purify/pure_api.c
security/sandbox/linux/SandboxAssembler.cpp
security/sandbox/linux/SandboxAssembler.h
xpcom/base/pure.h
xpcom/base/pure_api.c
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -795,21 +795,22 @@ getParentCB(AtkObject *aAtkObj)
     return aAtkObj->accessible_parent;
 
   AtkObject* atkParent = nullptr;
   if (AccessibleWrap* wrapper = GetAccessibleWrap(aAtkObj)) {
     Accessible* parent = wrapper->Parent();
     atkParent = parent ? AccessibleWrap::GetAtkObject(parent) : nullptr;
   } else if (ProxyAccessible* proxy = GetProxy(aAtkObj)) {
     ProxyAccessible* parent = proxy->Parent();
-    if (parent)
+    if (parent) {
       atkParent = GetWrapperFor(parent);
-
-    // Otherwise this should be the proxy for the tab's top level document.
-    atkParent = AccessibleWrap::GetAtkObject(proxy->OuterDocOfRemoteBrowser());
+    } else {
+      // Otherwise this should be the proxy for the tab's top level document.
+      atkParent = AccessibleWrap::GetAtkObject(proxy->OuterDocOfRemoteBrowser());
+    }
   }
 
   if (atkParent)
     atk_object_set_parent(aAtkObj, atkParent);
 
   return aAtkObj->accessible_parent;
 }
 
--- a/accessible/generic/DocAccessible.cpp
+++ b/accessible/generic/DocAccessible.cpp
@@ -451,17 +451,17 @@ DocAccessible::Shutdown()
   int32_t childDocCount = mChildDocuments.Length();
   for (int32_t idx = childDocCount - 1; idx >= 0; idx--)
     mChildDocuments[idx]->Shutdown();
 
   mChildDocuments.Clear();
 
   // XXX thinking about ordering?
   if (IPCAccessibilityActive()) {
-    DocAccessibleChild::Send__delete__(mIPCDoc);
+    mIPCDoc->Shutdown();
     MOZ_ASSERT(!mIPCDoc);
   }
 
   if (mVirtualCursor) {
     mVirtualCursor->RemoveObserver(this);
     mVirtualCursor = nullptr;
   }
 
--- a/accessible/ipc/DocAccessibleChild.cpp
+++ b/accessible/ipc/DocAccessibleChild.cpp
@@ -65,16 +65,19 @@ SerializeTree(Accessible* aRoot, nsTArra
 }
 
 Accessible*
 DocAccessibleChild::IdToAccessible(const uint64_t& aID) const
 {
   if (!aID)
     return mDoc;
 
+  if (!mDoc)
+    return nullptr;
+
   return mDoc->GetAccessibleByUniqueID(reinterpret_cast<void*>(aID));
 }
 
 Accessible*
 DocAccessibleChild::IdToAccessibleLink(const uint64_t& aID) const
 {
   Accessible* acc = IdToAccessible(aID);
   return acc && acc->IsLink() ? acc : nullptr;
@@ -220,17 +223,17 @@ DocAccessibleChild::PersistentProperties
   return true;
 }
 
 bool
 DocAccessibleChild::RecvRelationByType(const uint64_t& aID,
                                        const uint32_t& aType,
                                        nsTArray<uint64_t>* aTargets)
 {
-  Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
+  Accessible* acc = IdToAccessible(aID);
   if (!acc)
     return true;
 
   auto type = static_cast<RelationType>(aType);
   Relation rel = acc->RelationByType(type);
   while (Accessible* target = rel.Next())
     aTargets->AppendElement(reinterpret_cast<uintptr_t>(target));
 
@@ -253,17 +256,17 @@ AddRelation(Accessible* aAcc, RelationTy
     newRelation->Targets().SwapElements(targets);
   }
 }
 
 bool
 DocAccessibleChild::RecvRelations(const uint64_t& aID,
                                   nsTArray<RelationTargets>* aRelations)
 {
-  Accessible* acc = mDoc->GetAccessibleByUniqueID((void*)aID);
+  Accessible* acc = IdToAccessible(aID);
   if (!acc)
     return true;
 
 #define RELATIONTYPE(gecko, s, a, m, i) AddRelation(acc, RelationType::gecko, aRelations);
 
 #include "RelationTypeMap.h"
 #undef RELATIONTYPE
 
--- a/accessible/ipc/DocAccessibleChild.h
+++ b/accessible/ipc/DocAccessibleChild.h
@@ -27,18 +27,29 @@ class AccShowEvent;
 class DocAccessibleChild : public PDocAccessibleChild
 {
 public:
   explicit DocAccessibleChild(DocAccessible* aDoc) :
     mDoc(aDoc)
   { MOZ_COUNT_CTOR(DocAccessibleChild); }
   ~DocAccessibleChild()
   {
+    // Shutdown() should have been called, but maybe it isn't if the process is
+    // killed?
+    MOZ_ASSERT(!mDoc);
+    if (mDoc)
+      mDoc->SetIPCDoc(nullptr);
+    MOZ_COUNT_DTOR(DocAccessibleChild);
+  }
+
+  void Shutdown()
+  {
     mDoc->SetIPCDoc(nullptr);
-    MOZ_COUNT_DTOR(DocAccessibleChild);
+    mDoc = nullptr;
+    SendShutdown();
   }
 
   void ShowEvent(AccShowEvent* aShowEvent);
 
   /*
    * Return the state for the accessible with given ID.
    */
   virtual bool RecvState(const uint64_t& aID, uint64_t* aState) override;
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DocAccessibleParent.h"
 #include "nsAutoPtr.h"
 #include "mozilla/a11y/Platform.h"
 #include "ProxyAccessible.h"
+#include "mozilla/dom/TabParent.h"
 
 namespace mozilla {
 namespace a11y {
 
 bool
 DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
 {
   if (mShutdown)
@@ -181,16 +182,28 @@ DocAccessibleParent::AddChildDoc(DocAcce
 
 PLDHashOperator
 DocAccessibleParent::ShutdownAccessibles(ProxyEntry* entry, void*)
 {
   ProxyDestroyed(entry->mProxy);
   return PL_DHASH_REMOVE;
 }
 
+bool
+DocAccessibleParent::RecvShutdown()
+{
+  Destroy();
+
+  if (!static_cast<dom::TabParent*>(Manager())->IsDestroyed()) {
+  return PDocAccessibleParent::Send__delete__(this);
+  }
+
+  return true;
+}
+
 void
 DocAccessibleParent::Destroy()
 {
   NS_ASSERTION(mChildDocs.IsEmpty(),
                "why weren't the child docs destroyed already?");
   MOZ_ASSERT(!mShutdown);
   mShutdown = true;
 
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -54,16 +54,17 @@ public:
   virtual bool RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uint64_t& aID) override;
   void Unbind()
   {
     mParent = nullptr;
     ParentDoc()->mChildDocs.RemoveElement(this);
     mParentDoc = nullptr;
   }
 
+  virtual bool RecvShutdown() override;
   void Destroy();
   virtual void ActorDestroy(ActorDestroyReason aWhy) override
   {
     if (!mShutdown)
       Destroy();
   }
 
   /*
--- a/accessible/ipc/PDocAccessible.ipdl
+++ b/accessible/ipc/PDocAccessible.ipdl
@@ -43,17 +43,17 @@ struct RelationTargets
   uint64_t[] Targets;
 };
 
 prio(normal upto high) sync protocol PDocAccessible
 {
   manager PBrowser;
 
 parent:
-  __delete__();
+  Shutdown();
 
   /*
    * Notify the parent process the document in the child process is firing an
    * event.
    */
   Event(uint64_t aID, uint32_t type);
   ShowEvent(ShowEventData data);
   HideEvent(uint64_t aRootID);
@@ -62,16 +62,18 @@ parent:
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
+  __delete__();
+
   // Accessible
   prio(high) sync State(uint64_t aID) returns(uint64_t states);
   prio(high) sync Name(uint64_t aID) returns(nsString name);
   prio(high) sync Value(uint64_t aID) returns(nsString value);
   prio(high) sync Description(uint64_t aID) returns(nsString desc);
   prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
   prio(high) sync RelationByType(uint64_t aID, uint32_t aRelationType)
     returns(uint64_t[] targets);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1919,8 +1919,13 @@ pref("reader.parse-node-limit", 0);
 pref("browser.pocket.enabled", true);
 pref("browser.pocket.api", "api.getpocket.com");
 pref("browser.pocket.site", "getpocket.com");
 pref("browser.pocket.oAuthConsumerKey", "40249-e88c401e1b1f2242d9e441c4");
 pref("browser.pocket.useLocaleList", true);
 pref("browser.pocket.enabledLocales", "en-US de es-ES ja ja-JP-mac ru");
 
 pref("view_source.tab", true);
+
+// Enable Service Workers for desktop on non-release builds
+#ifndef RELEASE_BUILD
+pref("dom.serviceWorkers.enabled", true);
+#endif
index bfc718af6536e811bbfd6ed242da91f48df47f1a..2835ad347018d1ab8caa04eda40603bd781d781c
GIT binary patch
literal 65536
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
HAgKHgAd%oe
index bc41b88d88c852ef5ce9490e45df28918de115c7..ae47698b30a2afe073d9b7d4bdf3bc094794a346
GIT binary patch
literal 114688
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
--- a/build/pgo/server-locations.txt
+++ b/build/pgo/server-locations.txt
@@ -91,16 +91,17 @@ http://sub1.test2.example.com:80     pri
 http://sub2.test1.example.com:80     privileged
 http://sub2.test2.example.com:80     privileged
 http://noxul.example.com:80          privileged,noxul
 http://example.net:80                privileged
 # Used to test that clearing Service Workers for domain example.com, does not clear prefixexample.com
 http://prefixexample.com:80
 
 https://example.com:443                privileged
+https://example.org:443                privileged
 https://test1.example.com:443          privileged
 https://test2.example.com:443          privileged
 https://sub1.test1.example.com:443     privileged
 https://sub1.test2.example.com:443     privileged
 https://sub2.test1.example.com:443     privileged
 https://sub2.test2.example.com:443     privileged
 https://nocert.example.com:443         privileged,nocert
 https://self-signed.example.com:443    privileged,cert=selfsigned
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -242,16 +242,17 @@ nsString* nsContentUtils::sControlText =
 nsString* nsContentUtils::sMetaText = nullptr;
 nsString* nsContentUtils::sOSText = nullptr;
 nsString* nsContentUtils::sAltText = nullptr;
 nsString* nsContentUtils::sModifierSeparator = nullptr;
 
 bool nsContentUtils::sInitialized = false;
 bool nsContentUtils::sIsFullScreenApiEnabled = false;
 bool nsContentUtils::sTrustedFullScreenOnly = true;
+bool nsContentUtils::sIsCutCopyAllowed = true;
 bool nsContentUtils::sIsPerformanceTimingEnabled = false;
 bool nsContentUtils::sIsResourceTimingEnabled = false;
 bool nsContentUtils::sIsUserTimingLoggingEnabled = false;
 bool nsContentUtils::sIsExperimentalAutocompleteEnabled = false;
 bool nsContentUtils::sEncodeDecodeURLHash = false;
 
 uint32_t nsContentUtils::sHandlingInputTimeout = 1000;
 
@@ -509,16 +510,19 @@ nsContentUtils::Init()
                                "dom.allow_XUL_XBL_for_file");
 
   Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled,
                                "full-screen-api.enabled");
 
   Preferences::AddBoolVarCache(&sTrustedFullScreenOnly,
                                "full-screen-api.allow-trusted-requests-only");
 
+  Preferences::AddBoolVarCache(&sIsCutCopyAllowed,
+                               "dom.allow_cut_copy", true);
+
   Preferences::AddBoolVarCache(&sIsPerformanceTimingEnabled,
                                "dom.enable_performance", true);
 
   Preferences::AddBoolVarCache(&sIsResourceTimingEnabled,
                                "dom.enable_resource_timing", true);
 
   Preferences::AddBoolVarCache(&sIsUserTimingLoggingEnabled,
                                "dom.performance.enable_user_timing_logging", false);
@@ -6627,17 +6631,18 @@ nsContentUtils::IsRequestFullScreenAllow
          EventStateManager::IsHandlingUserInput() ||
          IsCallerChrome();
 }
 
 /* static */
 bool
 nsContentUtils::IsCutCopyAllowed()
 {
-  return EventStateManager::IsHandlingUserInput() ||
+  return (!IsCutCopyRestricted() &&
+          EventStateManager::IsHandlingUserInput()) ||
          IsCallerChrome();
 }
 
 /* static */
 bool
 nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
 {
   if (!aDoc1 || !aDoc2) {
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1859,16 +1859,25 @@ public:
    * Returns true if requests for full-screen are allowed in the current
    * context. Requests are only allowed if the user initiated them (like with
    * a mouse-click or key press), unless this check has been disabled by
    * setting the pref "full-screen-api.allow-trusted-requests-only" to false.
    */
   static bool IsRequestFullScreenAllowed();
 
   /**
+   * Returns true if calling execCommand with 'cut' or 'copy' arguments
+   * is restricted to chrome code.
+   */
+  static bool IsCutCopyRestricted()
+  {
+    return !sIsCutCopyAllowed;
+  }
+
+  /**
    * Returns true if calling execCommand with 'cut' or 'copy' arguments is
    * allowed in the current context. These are only allowed if the user initiated
    * them (like with a mouse-click or key press).
    */
   static bool IsCutCopyAllowed();
 
   /*
    * Returns true if the performance timing APIs are enabled.
@@ -2429,16 +2438,17 @@ private:
   static uint32_t sScriptBlockerCountWhereRunnersPrevented;
 
   static nsIInterfaceRequestor* sSameOriginChecker;
 
   static bool sIsHandlingKeyBoardEvent;
   static bool sAllowXULXBL_for_file;
   static bool sIsFullScreenApiEnabled;
   static bool sTrustedFullScreenOnly;
+  static bool sIsCutCopyAllowed;
   static uint32_t sHandlingInputTimeout;
   static bool sIsPerformanceTimingEnabled;
   static bool sIsResourceTimingEnabled;
   static bool sIsUserTimingLoggingEnabled;
   static bool sIsExperimentalAutocompleteEnabled;
   static bool sEncodeDecodeURLHash;
 
   static nsHtml5StringParser* sHTMLFragmentParser;
--- a/dom/cache/DBSchema.cpp
+++ b/dom/cache/DBSchema.cpp
@@ -24,21 +24,21 @@
 #include "mozilla/dom/ResponseBinding.h"
 #include "nsIContentPolicy.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 namespace db {
 
-const int32_t kMaxWipeSchemaVersion = 10;
+const int32_t kMaxWipeSchemaVersion = 11;
 
 namespace {
 
-const int32_t kLatestSchemaVersion = 10;
+const int32_t kLatestSchemaVersion = 11;
 const int32_t kMaxEntriesPerStatement = 255;
 
 const uint32_t kPageSize = 4 * 1024;
 
 // Grow the database in chunks to reduce fragmentation
 const uint32_t kGrowthSize = 32 * 1024;
 const uint32_t kGrowthPages = kGrowthSize / kPageSize;
 static_assert(kGrowthSize % kPageSize == 0,
@@ -296,16 +296,20 @@ CreateSchema(mozIStorageConnection* aCon
         "request_body_id TEXT NULL, "
         "response_type INTEGER NOT NULL, "
         "response_url TEXT NOT NULL, "
         "response_status INTEGER NOT NULL, "
         "response_status_text TEXT NOT NULL, "
         "response_headers_guard INTEGER NOT NULL, "
         "response_body_id TEXT NULL, "
         "response_security_info_id INTEGER NULL REFERENCES security_info(id), "
+        "response_redirected INTEGER NOT NULL, "
+        // Note that response_redirected_url is either going to be empty, or
+        // it's going to be a URL different than response_url.
+        "response_redirected_url TEXT NOT NULL, "
         "cache_id INTEGER NOT NULL REFERENCES caches(id) ON DELETE CASCADE"
       ");"
     ));
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
     // TODO: see if we can remove these indices on TEXT columns (bug 1110458)
     rv = aConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
       "CREATE INDEX entries_request_url_index "
@@ -1463,16 +1467,18 @@ InsertEntry(mozIStorageConnection* aConn
       "request_body_id, "
       "response_type, "
       "response_url, "
       "response_status, "
       "response_status_text, "
       "response_headers_guard, "
       "response_body_id, "
       "response_security_info_id, "
+      "response_redirected, "
+      "response_redirected_url, "
       "cache_id "
     ") VALUES ("
       ":request_method, "
       ":request_url, "
       ":request_url_no_query, "
       ":request_referrer, "
       ":request_headers_guard, "
       ":request_mode, "
@@ -1483,16 +1489,18 @@ InsertEntry(mozIStorageConnection* aConn
       ":request_body_id, "
       ":response_type, "
       ":response_url, "
       ":response_status, "
       ":response_status_text, "
       ":response_headers_guard, "
       ":response_body_id, "
       ":response_security_info_id, "
+      ":response_redirected, "
+      ":response_redirected_url, "
       ":cache_id "
     ");"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("request_method"),
                                    aRequest.method());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
@@ -1562,16 +1570,24 @@ InsertEntry(mozIStorageConnection* aConn
   if (aResponse.channelInfo().securityInfo().IsEmpty()) {
     rv = state->BindNullByName(NS_LITERAL_CSTRING("response_security_info_id"));
   } else {
     rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_security_info_id"),
                                 securityId);
   }
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
+  rv = state->BindInt32ByName(NS_LITERAL_CSTRING("response_redirected"),
+                              aResponse.channelInfo().redirected() ? 1 : 0);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  rv = state->BindUTF8StringByName(NS_LITERAL_CSTRING("response_redirected_url"),
+                                   aResponse.channelInfo().redirectedURI());
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
   rv = state->BindInt64ByName(NS_LITERAL_CSTRING("cache_id"), aCacheId);
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = state->Execute();
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT last_insert_rowid()"
@@ -1653,16 +1669,18 @@ ReadResponse(mozIStorageConnection* aCon
   nsresult rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "entries.response_type, "
       "entries.response_url, "
       "entries.response_status, "
       "entries.response_status_text, "
       "entries.response_headers_guard, "
       "entries.response_body_id, "
+      "entries.response_redirected, "
+      "entries.response_redirected_url, "
       "security_info.data "
     "FROM entries "
     "LEFT OUTER JOIN security_info "
     "ON entries.response_security_info_id=security_info.id "
     "WHERE entries.id=:id;"
   ), getter_AddRefs(state));
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
@@ -1700,17 +1718,25 @@ ReadResponse(mozIStorageConnection* aCon
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   aSavedResponseOut->mHasBodyId = !nullBody;
 
   if (aSavedResponseOut->mHasBodyId) {
     rv = ExtractId(state, 5, &aSavedResponseOut->mBodyId);
     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
   }
 
-  rv = state->GetBlobAsUTF8String(6, aSavedResponseOut->mValue.channelInfo().securityInfo());
+  int32_t redirected;
+  rv = state->GetInt32(6, &redirected);
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+  aSavedResponseOut->mValue.channelInfo().redirected() = !!redirected;
+
+  rv = state->GetUTF8String(7, aSavedResponseOut->mValue.channelInfo().redirectedURI());
+  if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
+
+  rv = state->GetBlobAsUTF8String(8, aSavedResponseOut->mValue.channelInfo().securityInfo());
   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
 
   rv = aConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT "
       "name, "
       "value "
     "FROM response_headers "
     "WHERE entry_id=:entry_id;"
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/TextEvents.h"
 #include "mozilla/dom/Element.h"
 #include "nsCaret.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsCopySupport.h"
 #include "nsFocusManager.h"
+#include "nsFontMetrics.h"
 #include "nsFrameSelection.h"
 #include "nsIContentIterator.h"
 #include "nsIPresShell.h"
 #include "nsISelection.h"
 #include "nsISelectionController.h"
 #include "nsISelectionPrivate.h"
 #include "nsIDOMRange.h"
 #include "nsIFrame.h"
@@ -1076,28 +1077,54 @@ ContentEventHandler::OnQueryCaretRect(Wi
   nsIFrame* frame;
   rv = GetStartFrameAndOffset(range, frame, xpOffsetInFrame);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsPoint posInFrame;
   rv = frame->GetPointFromOffset(range->StartOffset(), &posInFrame);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  aEvent->mReply.mWritingMode = frame->GetWritingMode();
+  bool isVertical = aEvent->mReply.mWritingMode.IsVertical();
+
   nsRect rect;
   rect.x = posInFrame.x;
   rect.y = posInFrame.y;
-  rect.width = caretRect.width;
-  rect.height = frame->GetSize().height;
+
+  nscoord fontHeight = 0;
+  float inflation = nsLayoutUtils::FontSizeInflationFor(frame);
+  nsRefPtr<nsFontMetrics> fontMetrics;
+  rv = nsLayoutUtils::GetFontMetricsForFrame(frame, getter_AddRefs(fontMetrics),
+                                             inflation);
+  if (NS_WARN_IF(!fontMetrics)) {
+    // If we cannot get font height, use frame size instead.
+    fontHeight = isVertical ? frame->GetSize().width : frame->GetSize().height;
+  } else {
+    fontHeight = fontMetrics->MaxAscent() + fontMetrics->MaxDescent();
+  }
+  if (isVertical) {
+    rect.width = fontHeight;
+    rect.height = caretRect.height;
+  } else {
+    rect.width = caretRect.width;
+    rect.height = fontHeight;
+  }
 
   rv = ConvertToRootViewRelativeOffset(frame, rect);
   NS_ENSURE_SUCCESS(rv, rv);
 
   aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
       rect.ToOutsidePixels(mPresContext->AppUnitsPerDevPixel()));
-  aEvent->mReply.mWritingMode = frame->GetWritingMode();
+  // If the caret rect is empty, let's make it non-empty rect.
+  if (!aEvent->mReply.mRect.width) {
+    aEvent->mReply.mRect.width = 1;
+  }
+  if (!aEvent->mReply.mRect.height) {
+    aEvent->mReply.mRect.height = 1;
+  }
   aEvent->mSucceeded = true;
   return NS_OK;
 }
 
 nsresult
 ContentEventHandler::OnQueryContentState(WidgetQueryContentEvent* aEvent)
 {
   nsresult rv = Init(aEvent);
--- a/dom/fetch/ChannelInfo.cpp
+++ b/dom/fetch/ChannelInfo.cpp
@@ -8,40 +8,58 @@
 #include "nsCOMPtr.h"
 #include "nsIChannel.h"
 #include "nsIHttpChannel.h"
 #include "nsSerializationHelper.h"
 #include "mozilla/net/HttpBaseChannel.h"
 #include "mozilla/ipc/ChannelInfo.h"
 #include "nsIJARChannel.h"
 #include "nsJARChannel.h"
+#include "nsNetUtil.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 void
 ChannelInfo::InitFromChannel(nsIChannel* aChannel)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
 
   nsCOMPtr<nsISupports> securityInfo;
   aChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
   if (securityInfo) {
     SetSecurityInfo(securityInfo);
   }
 
+  nsLoadFlags loadFlags = 0;
+  aChannel->GetLoadFlags(&loadFlags);
+  mRedirected = (loadFlags & nsIChannel::LOAD_REPLACE);
+  if (mRedirected) {
+    // Save the spec and not the nsIURI object itself, since those objects are
+    // not thread-safe, and releasing them somewhere other than the main thread
+    // is not possible.
+    nsCOMPtr<nsIURI> redirectedURI;
+    aChannel->GetURI(getter_AddRefs(redirectedURI));
+    if (redirectedURI) {
+      redirectedURI->GetSpec(mRedirectedURISpec);
+    }
+  }
+
   mInited = true;
 }
 
 void
 ChannelInfo::InitFromIPCChannelInfo(const ipc::IPCChannelInfo& aChannelInfo)
 {
   MOZ_ASSERT(!mInited, "Cannot initialize the object twice");
 
   mSecurityInfo = aChannelInfo.securityInfo();
+  mRedirectedURISpec = aChannelInfo.redirectedURI();
+  mRedirected = aChannelInfo.redirected();
 
   mInited = true;
 }
 
 void
 ChannelInfo::SetSecurityInfo(nsISupports* aSecurityInfo)
 {
   MOZ_ASSERT(mSecurityInfo.IsEmpty(), "security info should only be set once");
@@ -51,53 +69,83 @@ ChannelInfo::SetSecurityInfo(nsISupports
     return;
   }
   NS_SerializeToString(serializable, mSecurityInfo);
 }
 
 nsresult
 ChannelInfo::ResurrectInfoOnChannel(nsIChannel* aChannel)
 {
+  MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mInited);
 
+  // These pointers may be null at this point.  They must be checked before
+  // being dereferenced.
+  nsCOMPtr<nsIHttpChannel> httpChannel =
+    do_QueryInterface(aChannel);
+  nsCOMPtr<nsIJARChannel> jarChannel =
+    do_QueryInterface(aChannel);
+
   if (!mSecurityInfo.IsEmpty()) {
     nsCOMPtr<nsISupports> infoObj;
     nsresult rv = NS_DeserializeObject(mSecurityInfo, getter_AddRefs(infoObj));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
-    nsCOMPtr<nsIHttpChannel> httpChannel =
-      do_QueryInterface(aChannel);
     if (httpChannel) {
       net::HttpBaseChannel* httpBaseChannel =
         static_cast<net::HttpBaseChannel*>(httpChannel.get());
       rv = httpBaseChannel->OverrideSecurityInfo(infoObj);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
-      nsCOMPtr<nsIJARChannel> jarChannel =
-        do_QueryInterface(aChannel);
       if (NS_WARN_IF(!jarChannel)) {
         return NS_ERROR_FAILURE;
       }
       static_cast<nsJARChannel*>(jarChannel.get())->
         OverrideSecurityInfo(infoObj);
     }
   }
 
+  if (mRedirected) {
+    nsLoadFlags flags = 0;
+    aChannel->GetLoadFlags(&flags);
+    flags |= nsIChannel::LOAD_REPLACE;
+    aChannel->SetLoadFlags(flags);
+
+    nsCOMPtr<nsIURI> redirectedURI;
+    nsresult rv = NS_NewURI(getter_AddRefs(redirectedURI),
+                            mRedirectedURISpec);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    if (httpChannel) {
+      net::HttpBaseChannel* httpBaseChannel =
+        static_cast<net::HttpBaseChannel*>(httpChannel.get());
+      httpBaseChannel->OverrideURI(redirectedURI);
+    } else {
+      if (NS_WARN_IF(!jarChannel)) {
+        return NS_ERROR_FAILURE;
+      }
+      static_cast<nsJARChannel*>(jarChannel.get())->OverrideURI(redirectedURI);
+    }
+  }
+
   return NS_OK;
 }
 
 ipc::IPCChannelInfo
 ChannelInfo::AsIPCChannelInfo() const
 {
   // This may be called when mInited is false, for example if we try to store
   // a synthesized Response object into the Cache.  Uninitialized and empty
   // ChannelInfo objects are indistinguishable at the IPC level, so this is
   // fine.
 
   IPCChannelInfo ipcInfo;
 
   ipcInfo.securityInfo() = mSecurityInfo;
+  ipcInfo.redirectedURI() = mRedirectedURISpec;
+  ipcInfo.redirected() = mRedirected;
 
   return ipcInfo;
 }
--- a/dom/fetch/ChannelInfo.h
+++ b/dom/fetch/ChannelInfo.h
@@ -3,18 +3,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_ChannelInfo_h
 #define mozilla_dom_ChannelInfo_h
 
 #include "nsString.h"
+#include "nsCOMPtr.h"
 
 class nsIChannel;
+class nsIURI;
 
 namespace mozilla {
 namespace ipc {
 class IPCChannelInfo;
 } // namespace ipc
 
 namespace dom {
 
@@ -37,30 +39,35 @@ namespace dom {
 // initialized.  There are assertions ensuring these invariants.
 class ChannelInfo final
 {
 public:
   typedef mozilla::ipc::IPCChannelInfo IPCChannelInfo;
 
   ChannelInfo()
     : mInited(false)
+    , mRedirected(false)
   {
   }
 
   ChannelInfo(const ChannelInfo& aRHS)
     : mSecurityInfo(aRHS.mSecurityInfo)
+    , mRedirectedURISpec(aRHS.mRedirectedURISpec)
     , mInited(aRHS.mInited)
+    , mRedirected(aRHS.mRedirected)
   {
   }
 
   ChannelInfo&
   operator=(const ChannelInfo& aRHS)
   {
     mSecurityInfo = aRHS.mSecurityInfo;
+    mRedirectedURISpec = aRHS.mRedirectedURISpec;
     mInited = aRHS.mInited;
+    mRedirected = aRHS.mRedirected;
     return *this;
   }
 
   void InitFromChannel(nsIChannel* aChannel);
   void InitFromIPCChannelInfo(const IPCChannelInfo& aChannelInfo);
 
   // This restores every possible information stored from a previous channel
   // object on a new one.
@@ -73,15 +80,17 @@ public:
 
   IPCChannelInfo AsIPCChannelInfo() const;
 
 private:
   void SetSecurityInfo(nsISupports* aSecurityInfo);
 
 private:
   nsCString mSecurityInfo;
+  nsCString mRedirectedURISpec;
   bool mInited;
+  bool mRedirected;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_ChannelInfo_h
--- a/dom/fetch/ChannelInfo.ipdlh
+++ b/dom/fetch/ChannelInfo.ipdlh
@@ -3,12 +3,14 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 namespace mozilla {
 namespace ipc {
 
 struct IPCChannelInfo
 {
   nsCString securityInfo;
+  nsCString redirectedURI;
+  bool redirected;
 };
 
 } // namespace ipc
 } // namespace mozilla
--- a/dom/html/HTMLImageElement.cpp
+++ b/dom/html/HTMLImageElement.cpp
@@ -80,30 +80,35 @@ namespace dom {
 // Calls LoadSelectedImage on host element unless it has been superseded or
 // canceled -- this is the synchronous section of "update the image data".
 // https://html.spec.whatwg.org/multipage/embedded-content.html#update-the-image-data
 class ImageLoadTask : public nsRunnable
 {
 public:
   explicit ImageLoadTask(HTMLImageElement *aElement) :
     mElement(aElement)
-  {}
+  {
+    mDocument = aElement->OwnerDoc();
+    mDocument->BlockOnload();
+  }
 
   NS_IMETHOD Run()
   {
     if (mElement->mPendingImageLoadTask == this) {
       mElement->mPendingImageLoadTask = nullptr;
       mElement->LoadSelectedImage(true, true);
     }
+    mDocument->UnblockOnload(false);
     return NS_OK;
   }
 
 private:
   ~ImageLoadTask() {}
   nsRefPtr<HTMLImageElement> mElement;
+  nsCOMPtr<nsIDocument> mDocument;
 };
 
 HTMLImageElement::HTMLImageElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo)
   , mForm(nullptr)
 {
   // We start out broken
   AddStatesSilently(NS_EVENT_STATE_BROKEN);
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -3564,22 +3564,32 @@ nsHTMLDocument::QueryCommandSupported(co
 {
   *_retval = QueryCommandSupported(commandID);
   return NS_OK;
 }
 
 bool
 nsHTMLDocument::QueryCommandSupported(const nsAString& commandID)
 {
-  // Gecko technically supports the paste command, but non-privileged content
-  // will be unable to call it. For that reason, we report that paste is
-  // not supported to this non-privileged content (as it effectively is).
-  bool restricted = commandID.LowerCaseEqualsLiteral("paste");
-  if (restricted && !nsContentUtils::IsCallerChrome()) {
-    return false;
+  // Gecko technically supports all the clipboard commands including
+  // cut/copy/paste, but non-privileged content will be unable to call
+  // paste, and depending on the pref "dom.allow_cut_copy", cut and copy
+  // may also be disallowed to be called from non-privileged content.
+  // For that reason, we report the support status of corresponding
+  // command accordingly.
+  if (!nsContentUtils::IsCallerChrome()) {
+    if (commandID.LowerCaseEqualsLiteral("paste")) {
+      return false;
+    }
+    if (nsContentUtils::IsCutCopyRestricted()) {
+      if (commandID.LowerCaseEqualsLiteral("cut") ||
+          commandID.LowerCaseEqualsLiteral("copy")) {
+        return false;
+      }
+    }
   }
 
   // commandID is supported if it can be converted to a Midas command
   nsAutoCString cmdToDispatch;
   return ConvertToMidasInternalCommand(commandID, cmdToDispatch);
 }
 
 /* DOMString queryCommandValue(in DOMString commandID); */
--- a/dom/html/test/mochitest.ini
+++ b/dom/html/test/mochitest.ini
@@ -589,10 +589,9 @@ skip-if = buildapp == 'b2g' || e10s
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') || e10s #Bug 931116, b2g desktop specific, initial triage
 support-files = file_bug871161-1.html file_bug871161-2.html
 [test_bug1013316.html]
 [test_hash_encoded.html]
 [test_bug1081037.html]
 [test_window_open_close.html]
 skip-if = buildapp == 'b2g' # bug 1129014
 [test_img_complete.html]
-[test_viewport_resize.html]
-skip-if = os == 'win' || os == 'mac' # bug 1163911
\ No newline at end of file
+[test_viewport_resize.html]
\ No newline at end of file
--- a/dom/media/eme/MediaKeySession.h
+++ b/dom/media/eme/MediaKeySession.h
@@ -11,16 +11,17 @@
 #include "mozilla/ErrorResult.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/dom/Date.h"
 #include "mozilla/dom/Promise.h"
+#include "mozilla/DetailedPromise.h"
 #include "mozilla/dom/MediaKeySessionBinding.h"
 #include "mozilla/dom/MediaKeysBinding.h"
 #include "mozilla/dom/MediaKeyMessageEventBinding.h"
 
 struct JSContext;
 
 namespace mozilla {
 namespace dom {
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -99,8 +99,9 @@ skip-if = buildapp == 'mulet' || toolkit
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_windowedhistoryframes.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_navigation_timing.html]
 skip-if = buildapp == 'b2g' || buildapp == 'mulet'
 [test_bug1012662_editor.html]
 [test_bug1012662_noeditor.html]
 [test_bug1161721.html]
+[test_bug1170911.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_bug1170911.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1012662
+-->
+<head>
+  <title>Test for Bug 1170911</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170911">Mozilla Bug 1170911</a>
+<p id="display"></p>
+
+<div id="content">
+  <textarea>textarea text</textarea>
+</div>
+
+<pre id="test">
+<script>
+const TEXTAREA = document.querySelector('textarea');
+const TEXTAREA_VALUE = TEXTAREA.value;
+
+function doTest() {
+  is(document.queryCommandSupported("copy"), false,
+     "Copy support should have been disabled");
+  is(document.queryCommandSupported("cut"), false,
+     "Cut support should have been disabled");
+
+  document.addEventListener("keydown", tryCopy);
+  synthesizeKey("Q", {});
+}
+
+function tryCopy(evt) {
+  evt.preventDefault();
+  document.removeEventListener("keydown", tryCopy);
+  TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
+  TEXTAREA.focus();
+
+  SimpleTest.waitForClipboard(null, function () {
+      is(document.queryCommandEnabled("copy"), false,
+        "Copy should not be allowed when dom.allow_cut_copy is off");
+      is(document.execCommand("copy"), false,
+        "Copy should not be executed when dom.allow_cut_copy is off");
+      is(TEXTAREA.value, TEXTAREA_VALUE,
+        "Content in the textarea shouldn't be changed");
+      TEXTAREA.value = TEXTAREA_VALUE;
+    },
+    /* success fn */ SimpleTest.finish,
+    /* failure fn */ function () {
+      document.addEventListener("keydown", tryCut);
+      synthesizeKey("Q", {});
+    },
+    /* flavor */ undefined,
+    /* timeout */ undefined,
+    /* expect failure */ true);
+}
+
+function tryCut(evt) {
+  evt.preventDefault();
+  document.removeEventListener("keydown", tryCut);
+  TEXTAREA.setSelectionRange(0, TEXTAREA_VALUE.length);
+  TEXTAREA.focus();
+
+  SimpleTest.waitForClipboard(null, function () {
+      is(document.queryCommandEnabled("cut"), false,
+        "Cut should not be allowed when dom.allow_cut_copy is off");
+      is(document.execCommand("cut"), false,
+        "Cut should not be executed when dom.allow_cut_copy is off");
+      is(TEXTAREA.value, TEXTAREA_VALUE,
+        "Content in the textarea shouldn't be changed");
+    },
+    /* success fn */ SimpleTest.finish,
+    /* failure fn */ SimpleTest.finish,
+    /* flavor */ undefined,
+    /* timeout */ undefined,
+    /* expect failure */ true);
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(() => {
+  SpecialPowers.pushPrefEnv({"set": [["dom.allow_cut_copy", false]]}, doTest);
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -912,21 +912,21 @@ var interfaceNamesInGlobalScope =
     "Screen",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ScriptProcessorNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ScrollAreaEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Selection",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "ServiceWorker", disabled: true, b2g: false},
+    {name: "ServiceWorker", release: false, b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "ServiceWorkerContainer", disabled: true, b2g: false},
+    {name: "ServiceWorkerContainer", release: false, b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "ServiceWorkerRegistration", disabled: true, b2g: false},
+    {name: "ServiceWorkerRegistration", release: false, b2g: false},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SettingsLock",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SettingsManager",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "ShadowRoot", // Bogus, but the test harness forces it on.  See bug 1159768.
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "SharedWorker",
index 4cc5b89a08ef418e4b76784a174041392570442f..b179b0819cc03684676645149018a195b8b8790a
GIT binary patch
literal 3362
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
Qz7Wd;7_vXP?F;XJ0p~_hr2qf`
--- a/dom/workers/test/serviceworkers/app-protocol/controlled.html
+++ b/dom/workers/test/serviceworkers/app-protocol/controlled.html
@@ -12,15 +12,19 @@ function runTests() {
     .then(() => {
         return testFetchAppResource('foo.txt',
                                     'swresponse', 'text/plain');
     })
     .then(() => {
         return testFetchAppResource('test_custom_content_type',
                                     'customContentType', 'text/html');
     })
+    .then(testRedirectedResponse)
+    .then(testRedirectedHttpsResponse)
+    .then(testCachedRedirectedResponse)
+    .then(testCachedRedirectedHttpsResponse)
     .then(done);
 }
   </script>
   </head>
   <body onload='runTests()'>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/app-protocol/realindex.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+real index
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/app-protocol/realindex.html^headers^
@@ -0,0 +1,1 @@
+Access-Control-Allow-Origin: *
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/app-protocol/redirect-https.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response) {
+  response.setStatusLine(null, 308, "Permanent Redirect");
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
+  response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/app-protocol/redirect.sjs
@@ -0,0 +1,5 @@
+function handleRequest(request, response) {
+  response.setStatusLine(null, 308, "Permanent Redirect");
+  response.setHeader("Access-Control-Allow-Origin", "*", false);
+  response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/app-protocol/realindex.html", false);
+}
--- a/dom/workers/test/serviceworkers/app-protocol/sw.js
+++ b/dom/workers/test/serviceworkers/app-protocol/sw.js
@@ -1,8 +1,25 @@
+const kHTTPRedirect = "http://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect.sjs";
+const kHTTPSRedirect = "https://example.com/tests/dom/workers/test/serviceworkers/app-protocol/redirect-https.sjs";
+
+self.addEventListener('install', (event) => {
+  event.waitUntil(
+    self.caches.open("origin-app-cache")
+      .then(c => {
+        return Promise.all(
+          [
+            c.add(kHTTPRedirect),
+            c.add(kHTTPSRedirect),
+          ]
+        );
+      })
+  );
+});
+
 self.addEventListener('fetch', (event) => {
   if (event.request.url.indexOf('foo.txt') >= 0) {
     event.respondWith(new Response('swresponse', {
       headers: {'Content-Type': 'text/plain'}
     }));
   }
 
   if (event.request.url.indexOf('test_doc_load_interception.js') >= 0 ) {
@@ -12,9 +29,35 @@ self.addEventListener('fetch', (event) =
     }));
   }
 
   if (event.request.url.indexOf('test_custom_content_type') >= 0) {
     event.respondWith(new Response('customContentType', {
       headers: {'Content-Type': 'text/html'}
     }));
   }
+
+  if (event.request.url.indexOf('redirected.html') >= 0) {
+    event.respondWith(fetch(kHTTPRedirect));
+  }
+
+  if (event.request.url.indexOf('redirected-https.html') >= 0) {
+    event.respondWith(fetch(kHTTPSRedirect));
+  }
+
+  if (event.request.url.indexOf('redirected-cached.html') >= 0) {
+    event.respondWith(
+      self.caches.open("origin-app-cache")
+        .then(c => {
+          return c.match(kHTTPRedirect);
+        })
+    );
+  }
+
+  if (event.request.url.indexOf('redirected-https-cached.html') >= 0) {
+    event.respondWith(
+      self.caches.open("origin-app-cache")
+        .then(c => {
+          return c.match(kHTTPSRedirect);
+        })
+    );
+  }
 });
--- a/dom/workers/test/serviceworkers/app-protocol/test.js
+++ b/dom/workers/test/serviceworkers/app-protocol/test.js
@@ -32,8 +32,41 @@ function testFetchAppResource(aUrl,
          contentType + ' should match with ' + aExpectedContentType));
     }
     return res.text().then(body => {
       ok(body == aExpectedResponse, 'body ' + body +
          ' should match with ' + aExpectedResponse);
     });
   });
 }
+
+function testRedirectedResponse() {
+  return testRedirectedResponseWorker("redirected", "IFRAMELOADED");
+}
+
+function testRedirectedHttpsResponse() {
+  return testRedirectedResponseWorker("redirected-https", "HTTPSIFRAMELOADED");
+}
+
+function testCachedRedirectedResponse() {
+  return testRedirectedResponseWorker("redirected-cached", "IFRAMELOADED");
+}
+
+function testCachedRedirectedHttpsResponse() {
+  return testRedirectedResponseWorker("redirected-https-cached", "HTTPSIFRAMELOADED");
+}
+
+function testRedirectedResponseWorker(aFrameId, aAlert) {
+  // Because of the CSP policies applied to privileged apps, we cannot run
+  // inline script inside realindex.html, and loading a script from the app://
+  // URI is also not an option, so we let the parent iframe which has access
+  // to the SpecialPowers API use those privileges to access the document.
+  var iframe = document.createElement("iframe");
+  document.body.appendChild(iframe);
+  iframe.src = aFrameId + ".html";
+  iframe.id = aFrameId;
+  return new Promise(resolve => {
+    iframe.addEventListener("load", event => {
+      alert(aAlert);
+      resolve();
+    }, false);
+  });
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/index-https.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+  response.setStatusLine(null, 308, "Permanent Redirect");
+  response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/https/realindex.html", false);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/origin_test.js
@@ -0,0 +1,23 @@
+var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/https/";
+
+self.addEventListener("install", function(event) {
+  event.waitUntil(
+    self.caches.open("origin-cache")
+      .then(c => {
+        return c.add(prefix + 'index-https.sjs');
+      })
+  );
+});
+
+self.addEventListener("fetch", function(event) {
+  if (event.request.url.indexOf("index-cached-https.sjs") >= 0) {
+    event.respondWith(
+      self.caches.open("origin-cache")
+        .then(c => {
+          return c.match(prefix + 'index-https.sjs');
+        })
+    );
+  } else {
+    event.respondWith(fetch(event.request));
+  }
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/realindex.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+  window.opener.postMessage({status: "domain", data: document.domain}, "*");
+  window.opener.postMessage({status: "origin", data: location.origin}, "*");
+  window.opener.postMessage({status: "done"}, "*");
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/realindex.html^headers^
@@ -0,0 +1,1 @@
+Access-Control-Allow-Origin: https://example.com
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/register.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+  function ok(v, msg) {
+    window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
+  }
+
+  function done(reg) {
+    ok(reg.active, "The active worker should be available.");
+    window.parent.postMessage({status: "registrationdone"}, "*");
+  }
+
+  navigator.serviceWorker.ready.then(done);
+  navigator.serviceWorker.register("origin_test.js", {scope: "."});
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+  navigator.serviceWorker.getRegistration(".").then(function(registration) {
+    registration.unregister().then(function(success) {
+      if (success) {
+        window.parent.postMessage({status: "unregistrationdone"}, "*");
+      }
+    }, function(e) {
+      dump("Unregistering the SW failed with " + e + "\n");
+    });
+  });
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/index-to-https.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+  response.setStatusLine(null, 308, "Permanent Redirect");
+  response.setHeader("Location", "https://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/index.sjs
@@ -0,0 +1,4 @@
+function handleRequest(request, response) {
+  response.setStatusLine(null, 308, "Permanent Redirect");
+  response.setHeader("Location", "http://example.org/tests/dom/workers/test/serviceworkers/fetch/origin/realindex.html", false);
+}
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/origin_test.js
@@ -0,0 +1,35 @@
+var prefix = "/tests/dom/workers/test/serviceworkers/fetch/origin/";
+
+self.addEventListener("install", function(event) {
+  event.waitUntil(
+    self.caches.open("origin-cache")
+      .then(c => {
+        return Promise.all(
+          [
+            c.add(prefix + 'index.sjs'),
+            c.add(prefix + 'index-to-https.sjs'),
+          ]
+        );
+      })
+  );
+});
+
+self.addEventListener("fetch", function(event) {
+  if (event.request.url.indexOf("index-cached.sjs") >= 0) {
+    event.respondWith(
+      self.caches.open("origin-cache")
+        .then(c => {
+          return c.match(prefix + 'index.sjs');
+        })
+    );
+  } else if (event.request.url.indexOf("index-to-https-cached.sjs") >= 0) {
+    event.respondWith(
+      self.caches.open("origin-cache")
+        .then(c => {
+          return c.match(prefix + 'index-to-https.sjs');
+        })
+    );
+  } else {
+    event.respondWith(fetch(event.request));
+  }
+});
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/realindex.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+  window.opener.postMessage({status: "domain", data: document.domain}, "*");
+  window.opener.postMessage({status: "origin", data: location.origin}, "*");
+  window.opener.postMessage({status: "done"}, "*");
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/realindex.html^headers^
@@ -0,0 +1,1 @@
+Access-Control-Allow-Origin: http://mochi.test:8888
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/register.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+  function ok(v, msg) {
+    window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*");
+  }
+
+  function done(reg) {
+    ok(reg.active, "The active worker should be available.");
+    window.parent.postMessage({status: "registrationdone"}, "*");
+  }
+
+  navigator.serviceWorker.ready.then(done);
+  navigator.serviceWorker.register("origin_test.js", {scope: "."});
+</script>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/fetch/origin/unregister.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script>
+  navigator.serviceWorker.getRegistration(".").then(function(registration) {
+    registration.unregister().then(function(success) {
+      if (success) {
+        window.parent.postMessage({status: "unregistrationdone"}, "*");
+      }
+    }, function(e) {
+      dump("Unregistering the SW failed with " + e + "\n");
+    });
+  });
+</script>
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -42,16 +42,29 @@ support-files =
   fetch/https/index.html
   fetch/https/register.html
   fetch/https/unregister.html
   fetch/https/https_test.js
   fetch/https/clonedresponse/index.html
   fetch/https/clonedresponse/register.html
   fetch/https/clonedresponse/unregister.html
   fetch/https/clonedresponse/https_test.js
+  fetch/origin/index.sjs
+  fetch/origin/index-to-https.sjs
+  fetch/origin/realindex.html
+  fetch/origin/realindex.html^headers^
+  fetch/origin/register.html
+  fetch/origin/unregister.html
+  fetch/origin/origin_test.js
+  fetch/origin/https/index-https.sjs
+  fetch/origin/https/realindex.html
+  fetch/origin/https/realindex.html^headers^
+  fetch/origin/https/register.html
+  fetch/origin/https/unregister.html
+  fetch/origin/https/origin_test.js
   fetch/requesturl/index.html
   fetch/requesturl/redirect.sjs
   fetch/requesturl/redirector.html
   fetch/requesturl/register.html
   fetch/requesturl/requesturl_test.js
   fetch/requesturl/secret.html
   fetch/requesturl/unregister.html
   fetch/sandbox/index.html
@@ -154,8 +167,14 @@ support-files =
 [test_sanitize_domain.html]
 [test_service_worker_allowed.html]
 [test_app_protocol.html]
 [test_claim_fetch.html]
 [test_force_refresh.html]
 [test_skip_waiting.html]
 [test_strict_mode_error.html]
 [test_cross_origin_url_after_redirect.html]
+[test_origin_after_redirect.html]
+[test_origin_after_redirect_cached.html]
+[test_origin_after_redirect_to_https.html]
+[test_origin_after_redirect_to_https_cached.html]
+[test_https_origin_after_redirect.html]
+[test_https_origin_after_redirect_cached.html]
--- a/dom/workers/test/serviceworkers/test_app_protocol.html
+++ b/dom/workers/test/serviceworkers/test_app_protocol.html
@@ -23,17 +23,18 @@ let gApp;
 
 function setup() {
   return new Promise((resolve, reject) => {
     SpecialPowers.setAllAppsLaunchable(true);
     SpecialPowers.pushPrefEnv({'set': [
       ['dom.mozBrowserFramesEnabled', true],
       ['dom.serviceWorkers.exemptFromPerDomainMax', true],
       ['dom.serviceWorkers.enabled', true],
-      ['dom.serviceWorkers.testing.enabled', true]
+      ['dom.serviceWorkers.testing.enabled', true],
+      ['dom.caches.enabled', true],
     ]}, () => {
       SpecialPowers.pushPermissions([
         { 'type': 'webapps-manage', 'allow': 1, 'context': document },
         { 'type': 'browser', 'allow': 1, 'context': document },
         { 'type': 'embed-apps', 'allow': 1, 'context': document }
       ], () => {
         SpecialPowers.autoConfirmAppInstall(() => {
           SpecialPowers.autoConfirmAppUninstall(resolve);
@@ -98,16 +99,28 @@ function loadControlled() {
     iframe.setAttribute('mozbrowser', 'true');
     iframe.setAttribute('mozapp', gApp.manifestURL);
     iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
       let message = e.detail.message;
       if (/OK/.exec(message)) {
         ok(true, "Message from app: " + message);
       } else if (/KO/.exec(message)) {
         ok(false, "Message from app: " + message);
+      } else if (/HTTPSIFRAMELOADED/.exec(message)) {
+        let doc = SpecialPowers.wrap(iframe).contentDocument;
+        let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected-https").contentDocument);
+        let innerLocation = innerDoc.defaultView.location;
+        is(innerDoc.domain, "example.org", "Correct domain expected (https)");
+        is(innerLocation.origin, "https://example.org", "Correct origin expected (https)");
+      } else if (/IFRAMELOADED/.exec(message)) {
+        let doc = SpecialPowers.wrap(iframe).contentDocument;
+        let innerDoc = SpecialPowers.wrap(doc.getElementById("redirected").contentDocument);
+        let innerLocation = innerDoc.defaultView.location;
+        is(innerDoc.domain, "example.org", "Correct domain expected");
+        is(innerLocation.origin, "http://example.org", "Correct origin expected");
       } else if (/DONE/.exec(message)) {
         ok(true, "Messaging from app complete");
         iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
         let domParent = document.getElementById('container');
         domParent.removeChild(iframe);
         resolve();
       } else {
         ok(false, "Unexpected message received: " + message);
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_https_origin_after_redirect.html
@@ -0,0 +1,56 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-https.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "https://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_https_origin_after_redirect_cached.html
@@ -0,0 +1,56 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/index-cached-https.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "https://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/origin/https/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_origin_after_redirect.html
@@ -0,0 +1,57 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "http://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.serviceWorkers.testing.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_origin_after_redirect_cached.html
@@ -0,0 +1,57 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-cached.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "http://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.serviceWorkers.testing.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_origin_after_redirect_to_https.html
@@ -0,0 +1,57 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "https://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.serviceWorkers.testing.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_origin_after_redirect_to_https_cached.html
@@ -0,0 +1,57 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test the origin of a redirected response from a service worker</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none">
+<iframe></iframe>
+</div>
+<pre id="test"></pre>
+<script class="testbody" type="text/javascript">
+
+  var iframe;
+  function runTest() {
+    iframe = document.querySelector("iframe");
+    iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/register.html";
+    var win;
+    window.onmessage = function(e) {
+      if (e.data.status == "ok") {
+        ok(e.data.result, e.data.message);
+      } else if (e.data.status == "registrationdone") {
+        win = window.open("/tests/dom/workers/test/serviceworkers/fetch/origin/index-to-https-cached.sjs", "mywindow", "width=100,height=100");
+      } else if (e.data.status == "domain") {
+        is(e.data.data, "example.org", "Correct domain expected");
+      } else if (e.data.status == "origin") {
+        is(e.data.data, "https://example.org", "Correct origin expected");
+      } else if (e.data.status == "done") {
+        win.close();
+        iframe.src = "/tests/dom/workers/test/serviceworkers/fetch/origin/unregister.html";
+      } else if (e.data.status == "unregistrationdone") {
+        window.onmessage = null;
+        ok(true, "Test finished successfully");
+        SimpleTest.finish();
+      }
+    };
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  onload = function() {
+    SpecialPowers.pushPrefEnv({"set": [
+      ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+      ["dom.serviceWorkers.enabled", true],
+      ["dom.serviceWorkers.testing.enabled", true],
+      ["dom.caches.enabled", true],
+    ]}, runTest);
+  };
+</script>
+</pre>
+</body>
+</html>
--- a/dom/workers/test/test_worker_interfaces.js
+++ b/dom/workers/test/test_worker_interfaces.js
@@ -152,17 +152,17 @@ var interfaceNamesInGlobalScope =
     "PerformanceMeasure",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Promise",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Request",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Response",
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    { name: "ServiceWorkerRegistration", disabled: true, b2g: false },
+    { name: "ServiceWorkerRegistration", release: false, b2g: false },
 // 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",
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2241,17 +2241,17 @@ gfxPlatform::OptimalFormatForContent(gfx
  * There are a number of layers acceleration (or layers in general) preferences
  * that should be consistent for the lifetime of the application (bug 840967).
  * As such, we will evaluate them all as soon as one of them is evaluated
  * and remember the values.  Changing these preferences during the run will
  * not have any effect until we restart.
  */
 static bool sLayersSupportsD3D9 = false;
 static bool sLayersSupportsD3D11 = false;
-static bool sANGLESupportsD3D11 = false;
+bool gANGLESupportsD3D11 = false;
 static bool sLayersSupportsHardwareVideoDecoding = false;
 static bool sLayersHardwareVideoDecodingFailed = false;
 static bool sBufferRotationCheckPref = true;
 static bool sPrefBrowserTabsRemoteAutostart = false;
 
 static bool sLayersAccelerationPrefsInitialized = false;
 
 void
@@ -2286,17 +2286,17 @@ InitLayersAccelerationPrefs()
         }
       }
       if (!gfxPrefs::LayersD3D11DisableWARP()) {
         // Always support D3D11 when WARP is allowed.
         sLayersSupportsD3D11 = true;
       }
       if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE, &status))) {
         if (status == nsIGfxInfo::FEATURE_STATUS_OK) {
-          sANGLESupportsD3D11 = true;
+          gANGLESupportsD3D11 = true;
         }
       }
     }
 #endif
 
     if (Preferences::GetBool("media.hardware-video-decoding.enabled", false) &&
 #ifdef XP_WIN
         Preferences::GetBool("media.windows-media-foundation.use-dxva", true) &&
@@ -2342,17 +2342,17 @@ gfxPlatform::CanUseHardwareVideoDecoding
   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
   return sLayersSupportsHardwareVideoDecoding && !sLayersHardwareVideoDecodingFailed;
 }
 
 bool
 gfxPlatform::CanUseDirect3D11ANGLE()
 {
   MOZ_ASSERT(sLayersAccelerationPrefsInitialized);
-  return sANGLESupportsD3D11;
+  return gANGLESupportsD3D11;
 }
 
 
 bool
 gfxPlatform::BufferRotationEnabled()
 {
   MutexAutoLock autoLock(*gGfxPlatformPrefsLock);
 
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -126,16 +126,18 @@ enum eGfxLog {
     eGfxLog_cmapdata         = 4,
     // text perf data
     eGfxLog_textperf         = 5
 };
 
 // when searching through pref langs, max number of pref langs
 const uint32_t kMaxLenPrefLangList = 32;
 
+extern bool gANGLESupportsD3D11;
+
 #define UNINITIALIZED_VALUE  (-1)
 
 inline const char*
 GetBackendName(mozilla::gfx::BackendType aBackend)
 {
   switch (aBackend) {
       case mozilla::gfx::BackendType::DIRECT2D:
         return "direct2d";
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -572,17 +572,22 @@ static CVReturn VsyncCallback(CVDisplayL
   // Executed on OS X hardware vsync thread
   OSXVsyncSource::OSXDisplay* display = (OSXVsyncSource::OSXDisplay*) aDisplayLinkContext;
   int64_t nextVsyncTimestamp = aOutputTime->hostTime;
   mozilla::TimeStamp nextVsync = mozilla::TimeStamp::FromSystemTime(nextVsyncTimestamp);
 
   mozilla::TimeStamp previousVsync = display->mPreviousTimestamp;
   display->mPreviousTimestamp = nextVsync;
   mozilla::TimeStamp now = TimeStamp::Now();
-  MOZ_ASSERT(nextVsync > previousVsync);
+  if (nextVsync <= previousVsync) {
+    TimeDuration next = nextVsync - now;
+    TimeDuration prev = now - previousVsync;
+    printf_stderr("Next from now: %f, prev from now: %f\n", next.ToMilliseconds(), prev.ToMilliseconds());
+    MOZ_ASSERT(false, "Next vsync less than previous vsync\n");
+  }
 
   // Bug 1158321 - The VsyncCallback can sometimes execute before the reported
   // vsync time. In those cases, normalize the timestamp to Now() as sending
   // timestamps in the future has undefined behavior. See the comment above
   // OSXDisplay::mPreviousTimestamp
   if (now < previousVsync) {
     previousVsync = now;
   }
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1713,22 +1713,24 @@ bool DoesD3D11DeviceWork(ID3D11Device *d
   if (GetModuleHandleW(L"dlumd32.dll") && GetModuleHandleW(L"igd10umd32.dll")) {
     nsString displayLinkModuleVersionString;
     gfxWindowsPlatform::GetDLLVersion(L"dlumd32.dll", displayLinkModuleVersionString);
     uint64_t displayLinkModuleVersion;
     if (!ParseDriverVersion(displayLinkModuleVersionString, &displayLinkModuleVersion)) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: could not parse version\n"));
 #endif
+      gANGLESupportsD3D11 = false;
       return false;
     }
     if (displayLinkModuleVersion <= V(8,6,1,36484)) {
 #if defined(MOZ_CRASHREPORTER)
       CrashReporter::AppendAppNotesToCrashReport(NS_LITERAL_CSTRING("DisplayLink: too old version\n"));
 #endif
+      gANGLESupportsD3D11 = false;
       return false;
     }
   }
   result = true;
   return true;
 }
 
 // See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails
--- a/intl/uconv/tests/unit/test_bug399257.js
+++ b/intl/uconv/tests/unit/test_bug399257.js
@@ -1,68 +1,66 @@
 // Tests encoding of characters below U+0020
 load('CharsetConversionTests.js');
 
 const inString = "Hello\u000aWorld";
 const expectedString = "Hello\nWorld";
 
 function run_test() {
     var failures = false;
+    var encodingConverter = CreateScriptableConverter();
 
-    var decoders = [
+    var encoders = [
         "Big5",
         "Big5-HKSCS",
         "EUC-JP",
         "EUC-KR",
         "gb18030",
+        "gbk",
         "IBM866",
         "ISO-2022-JP",
+        "ISO-8859-1",
+        "ISO-8859-2",
         "ISO-8859-3",
         "ISO-8859-4",
         "ISO-8859-5",
         "ISO-8859-6",
         "ISO-8859-7",
         "ISO-8859-8",
         "ISO-8859-8-I",
         "ISO-8859-10",
         "ISO-8859-13",
         "ISO-8859-14",
         "ISO-8859-15",
         "ISO-8859-16",
-        "ISO-8859-2",
         "KOI8-R",
         "KOI8-U",
         "Shift_JIS",
         "windows-1250",
         "windows-1251",
         "windows-1252",
         "windows-1253",
         "windows-1254",
         "windows-1255",
         "windows-1256",
         "windows-1257",
         "windows-1258",
         "windows-874",
+        "macintosh",
         "x-mac-cyrillic",
+        "x-user-defined",
         "UTF-8"
     ];
 
     var counter = 0;
-    while (counter < decoders.length) {
-	++counter;
-	var charset = decoders[counter];
-
+    while (counter < encoders.length) {
+	var charset = encoders[counter++];
         dump("testing " + counter + " " + charset + "\n");
 
-        try {
-            encodingConverter.charset = charset;
-        } catch(e) {
-            dump("Warning: couldn't set encoder charset to " + charset + "\n");
-            continue;
-        }
+        encodingConverter.charset = charset;
         var codepageString = encodingConverter.ConvertFromUnicode(inString) +
             encodingConverter.Finish();
 	if (codepageString != expectedString) {
 	    dump(charset + " encoding failed\n");
 	    for (var i = 0; i < expectedString.length; ++i) {
 		if (codepageString.charAt(i) != expectedString.charAt(i)) {
 		    dump(i.toString(16) + ": 0x" +
 			 codepageString.charCodeAt(i).toString(16) + " != " +
--- a/intl/uconv/tests/unit/test_bug601429.js
+++ b/intl/uconv/tests/unit/test_bug601429.js
@@ -1,65 +1,63 @@
 // Tests whether characters above 0x7F decode to ASCII characters liable to 
 // expose XSS vulnerabilities
 load('CharsetConversionTests.js');
 
 function run_test() {
   var failures = false;
+  var decodingConverter = CreateScriptableConverter();
 
   var decoders = [
     "Big5",
     "Big5-HKSCS",
     "EUC-JP",
     "EUC-KR",
     "gb18030",
     "IBM866",
     "ISO-2022-JP",
+    "ISO-8859-1",
+    "ISO-8859-2",
     "ISO-8859-3",
     "ISO-8859-4",
     "ISO-8859-5",
     "ISO-8859-6",
     "ISO-8859-7",
     "ISO-8859-8",
     "ISO-8859-8-I",
     "ISO-8859-10",
     "ISO-8859-13",
     "ISO-8859-14",
     "ISO-8859-15",
     "ISO-8859-16",
-    "ISO-8859-2",
     "KOI8-R",
     "KOI8-U",
     "Shift_JIS",
     "windows-1250",
     "windows-1251",
     "windows-1252",
     "windows-1253",
     "windows-1254",
     "windows-1255",
     "windows-1256",
     "windows-1257",
     "windows-1258",
     "windows-874",
+    "macintosh",
     "x-mac-cyrillic",
+    "x-user-defined",
     "UTF-8"
   ];
 
   var counter = 0;
   while (counter < decoders.length) {
-    ++counter;
-    var charset = decoders[counter];
+    var charset = decoders[counter++];
     dump("testing " + counter + " " + charset + "\n");
-      
-    try {
-      decodingConverter.charset = charset;
-    } catch(e) {
-      dump("Warning: couldn't set decoder charset to " + charset + "\n");
-      continue;
-    }
+
+    decodingConverter.charset = charset;
     for (var i = 0x80; i < 0x100; ++i) {
       var inString = String.fromCharCode(i);
       var outString;
       try {
 	outString = decodingConverter.ConvertToUnicode(inString) +
 	                decodingConverter.Finish();
       } catch(e) {
 	outString = String.fromCharCode(0xFFFD);
--- a/intl/uconv/tests/unit/test_encode_gbk.js
+++ b/intl/uconv/tests/unit/test_encode_gbk.js
@@ -1,15 +1,15 @@
 // Tests conversion from Unicode to gbk
 // This is a sniff test which doesn't cover the full gbk range: the test string
 // includes only the ASCII range and the first 63 double byte characters
 
 load('CharsetConversionTests.js');
 	
 const inString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u20AC\u4E02\u4E04\u4E05\u4E06\u4E0F\u4E12\u4E17\u4E1F\u4E20\u4E21\u4E23\u4E26\u4E29\u4E2E\u4E2F\u4E31\u4E33\u4E35\u4E37\u4E3C\u4E40\u4E41\u4E42\u4E44\u4E46\u4E4A\u4E51\u4E55\u4E57\u4E5A\u4E5B\u4E62\u4E63\u4E64\u4E65\u4E67\u4E68\u4E6A\u4E6B\u4E6C\u4E6D\u4E6E\u4E6F\u4E72\u4E74\u4E75\u4E76\u4E77\u4E78\u4E79\u4E7A\u4E7B\u4E7C\u4E7D\u4E7F\u4E80\u4E81\u4E82\u4E83\u4E84\u4E85\u4E87\u4E8A\uFFFD";
 
-const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81@\x81A\x81B\x81C\x81D\x81E\x81F\x81G\x81H\x81I\x81J\x81K\x81L\x81M\x81N\x81O\x81P\x81Q\x81R\x81S\x81T\x81U\x81V\x81W\x81X\x81Y\x81Z\x81[\x81\\\x81]\x81^\x81_\x81`\x81a\x81b\x81c\x81d\x81e\x81f\x81g\x81h\x81i\x81j\x81k\x81l\x81m\x81n\x81o\x81p\x81q\x81r\x81s\x81t\x81u\x81v\x81w\x81x\x81y\x81z\x81{\x81|\x81}\x81~";
+const expectedString = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x80\x81@\x81A\x81B\x81C\x81D\x81E\x81F\x81G\x81H\x81I\x81J\x81K\x81L\x81M\x81N\x81O\x81P\x81Q\x81R\x81S\x81T\x81U\x81V\x81W\x81X\x81Y\x81Z\x81[\x81\\\x81]\x81^\x81_\x81`\x81a\x81b\x81c\x81d\x81e\x81f\x81g\x81h\x81i\x81j\x81k\x81l\x81m\x81n\x81o\x81p\x81q\x81r\x81s\x81t\x81u\x81v\x81w\x81x\x81y\x81z\x81{\x81|\x81}\x81~?";
     
 const aliases = [ "gbk", "x-gbk" ];
 
 function run_test() {
   testEncodeAliases();
 }
new file mode 100644
--- /dev/null
+++ b/intl/uconv/tests/unit/test_unmapped.js
@@ -0,0 +1,77 @@
+// Tests encoding of unmapped characters
+load('CharsetConversionTests.js');
+
+const inString = "\u2764";
+const expectedString = "?";
+
+function run_test() {
+    var failures = false;
+    var encodingConverter = CreateScriptableConverter();
+
+    // this list excludes codepages that can represent all Unicode
+    var encoders = [
+        "Big5",
+        "Big5-HKSCS",
+        "EUC-JP",
+        "EUC-KR",
+        "gbk",
+        "IBM866",
+        "ISO-2022-JP",
+        "ISO-8859-3",
+        "ISO-8859-4",
+        "ISO-8859-5",
+        "ISO-8859-6",
+        "ISO-8859-7",
+        "ISO-8859-8",
+        "ISO-8859-8-I",
+        "ISO-8859-10",
+        "ISO-8859-13",
+        "ISO-8859-14",
+        "ISO-8859-15",
+        "ISO-8859-16",
+        "ISO-8859-2",
+        "KOI8-R",
+        "KOI8-U",
+        "Shift_JIS",
+        "windows-1250",
+        "windows-1251",
+        "windows-1252",
+        "windows-1253",
+        "windows-1254",
+        "windows-1255",
+        "windows-1256",
+        "windows-1257",
+        "windows-1258",
+        "windows-874",
+        "x-mac-cyrillic"
+    ];
+
+    var counter = 0;
+    while (counter < encoders.length) {
+        var charset = encoders[counter++];
+
+        dump("testing " + counter + " " + charset + "\n");
+        encodingConverter.charset = charset;
+        var codepageString = encodingConverter.ConvertFromUnicode(inString) +
+            encodingConverter.Finish();
+        if (codepageString != expectedString) {
+            dump(charset + " encoding failed\n");
+            for (var i = 0; i < expectedString.length; ++i) {
+                if (i >= codepageString.length) {
+                    dump("output length " + codepageString.length +
+                         " less than expected length " + expectedString.length + "\n");
+                    break;
+                }
+                if (codepageString.charAt(i) != expectedString.charAt(i)) {
+                    dump(i.toString(16) + ": 0x" +
+                         codepageString.charCodeAt(i).toString(16) + " != " +
+                         expectedString.charCodeAt(i).toString(16) + "\n");
+                }
+            }
+            failures = true;
+        }
+    }
+    if (failures) {
+        do_throw("test failed\n");
+    }
+}
--- a/intl/uconv/tests/unit/xpcshell.ini
+++ b/intl/uconv/tests/unit/xpcshell.ini
@@ -115,8 +115,9 @@ support-files =
 [test_encode_x_mac_hebrew.js]
 [test_encode_x_mac_icelandic.js]
 [test_encode_macintosh.js]
 [test_encode_x_mac_romanian.js]
 [test_encode_x_mac_turkish.js]
 [test_utf8_illegals.js]
 [test_input_stream.js]
 [test_bug1008832.js]
+[test_unmapped.js]
--- a/intl/uconv/ucvcn/nsUnicodeToGBK.cpp
+++ b/intl/uconv/ucvcn/nsUnicodeToGBK.cpp
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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/. */
  /**
  * A character set converter from Unicode to GBK.
  * 
  *
  * @created         08/Sept/1999
@@ -74,40 +74,45 @@ void nsUnicodeToGB18030::CreateExtension
 {
   mExtensionEncoder = new nsUnicodeToGB18030Uniq2Bytes();
 }
 void nsUnicodeToGB18030::Create4BytesEncoder()
 {
   m4BytesEncoder = new nsUnicodeTo4BytesGB18030();
 }
 
-bool nsUnicodeToGB18030::EncodeSurrogate(
-  char16_t aSurrogateHigh,
-  char16_t aSurrogateLow,
-  char* aOut)
+nsresult nsUnicodeToGB18030::EncodeSurrogate(char16_t aSurrogateHigh,
+                                             char16_t aSurrogateLow,
+                                             char* aOut,
+                                             int32_t aDestLength,
+                                             int32_t aBufferLength)
 {
-  if( NS_IS_HIGH_SURROGATE(aSurrogateHigh) && 
+  if( NS_IS_HIGH_SURROGATE(aSurrogateHigh) &&
       NS_IS_LOW_SURROGATE(aSurrogateLow) )
   {
-    // notice that idx does not include the 0x10000 
+    // notice that idx does not include the 0x10000
     uint32_t idx = ((aSurrogateHigh - (char16_t)0xD800) << 10 ) |
                    (aSurrogateLow - (char16_t) 0xDC00);
 
+    if (aDestLength + 4 > aBufferLength) {
+      return NS_OK_UENC_MOREOUTPUT;
+    }
+
     unsigned char *out = (unsigned char*) aOut;
-    // notice this is from 0x90 for supplment planes
-    out[0] = (idx / (10*126*10)) + 0x90; 
+    // notice this is from 0x90 for supplementary planes
+    out[0] = (idx / (10*126*10)) + 0x90;
     idx %= (10*126*10);
     out[1] = (idx / (10*126)) + 0x30;
     idx %= (10*126);
     out[2] = (idx / (10)) + 0x81;
     out[3] = (idx % 10) + 0x30;
-    return true;
-  } 
-  return false; 
-} 
+    return NS_OK;
+  }
+  return NS_ERROR_UENC_NOMAPPING;
+}
 
 //----------------------------------------------------------------------
 // Class nsUnicodeToGBK [implementation]
 
 nsUnicodeToGBK::nsUnicodeToGBK(uint32_t aMaxLength) :
   nsEncoderSupport(aMaxLength)
 {
   mExtensionEncoder = nullptr;
@@ -117,80 +122,76 @@ nsUnicodeToGBK::nsUnicodeToGBK(uint32_t 
 void nsUnicodeToGBK::CreateExtensionEncoder()
 {
   mExtensionEncoder = new nsUnicodeToGBKUniq();
 }
 void nsUnicodeToGBK::Create4BytesEncoder()
 {
   m4BytesEncoder = nullptr;
 }
-bool nsUnicodeToGBK::TryExtensionEncoder(
+
+nsresult nsUnicodeToGBK::TryExtensionEncoder(char16_t aChar,
+                                             char* aOut,
+                                             int32_t *aOutLen)
+{
+  if( NS_IS_HIGH_SURROGATE(aChar) ||
+      NS_IS_LOW_SURROGATE(aChar) )
+  {
+    // performance tune for surrogate characters
+    return NS_ERROR_UENC_NOMAPPING;
+  }
+  if(! mExtensionEncoder )
+    CreateExtensionEncoder();
+  if(mExtensionEncoder)
+  {
+    int32_t len = 1;
+    return mExtensionEncoder->Convert(&aChar, &len, aOut, aOutLen);
+  }
+  return NS_ERROR_UENC_NOMAPPING;
+}
+
+nsresult nsUnicodeToGBK::Try4BytesEncoder(
   char16_t aChar,
   char* aOut,
   int32_t *aOutLen
 )
 {
-  if( NS_IS_HIGH_SURROGATE(aChar) || 
+  if( NS_IS_HIGH_SURROGATE(aChar) ||
       NS_IS_LOW_SURROGATE(aChar) )
   {
     // performance tune for surrogate characters
-    return false;
-  }
-  if(! mExtensionEncoder )
-    CreateExtensionEncoder();
-  if(mExtensionEncoder) 
-  {
-    int32_t len = 1;
-    nsresult res = NS_OK;
-    res = mExtensionEncoder->Convert(&aChar, &len, aOut, aOutLen);
-    if(NS_SUCCEEDED(res) && (*aOutLen > 0))
-      return true;
-  }
-  return false;
-}
-
-bool nsUnicodeToGBK::Try4BytesEncoder(
-  char16_t aChar,
-  char* aOut,
-  int32_t *aOutLen
-)
-{
-  if( NS_IS_HIGH_SURROGATE(aChar) || 
-      NS_IS_LOW_SURROGATE(aChar) )
-  {
-    // performance tune for surrogate characters
-    return false;
+    return NS_ERROR_UENC_NOMAPPING;
   }
   if(! m4BytesEncoder )
     Create4BytesEncoder();
-  if(m4BytesEncoder) 
+  if(m4BytesEncoder)
   {
     int32_t len = 1;
     nsresult res = NS_OK;
     res = m4BytesEncoder->Convert(&aChar, &len, aOut, aOutLen);
     NS_ASSERTION(NS_FAILED(res) || ((1 == len) && (4 == *aOutLen)),
       "unexpect conversion length");
-    if(NS_SUCCEEDED(res) && (*aOutLen > 0))
-      return true;
+    return res;
   }
-  return false;
+  return NS_ERROR_UENC_NOMAPPING;
 }
-bool nsUnicodeToGBK::EncodeSurrogate(
-  char16_t aSurrogateHigh,
-  char16_t aSurrogateLow,
-  char* aOut)
+
+nsresult nsUnicodeToGBK::EncodeSurrogate(char16_t aSurrogateHigh,
+                                         char16_t aSurrogateLow,
+                                         char* aOut,
+                                         int32_t aDestLength,
+                                         int32_t aBufferLength)
 {
-  return false; // GBK cannot encode Surrogate, let the subclass encode it.
-} 
+  return NS_ERROR_UENC_NOMAPPING; // GBK cannot encode Surrogate, let the subclass encode it.
+}
 
-NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuff(
-  const char16_t * aSrc, 
-  int32_t * aSrcLength, 
-  char * aDest, 
-  int32_t * aDestLength)
+NS_IMETHODIMP nsUnicodeToGBK::ConvertNoBuffNoErr(const char16_t * aSrc,
+                                                 int32_t * aSrcLength,
+                                                 char * aDest,
+                                                 int32_t * aDestLength)
 {
   int32_t iSrcLength = 0;
   int32_t iDestLength = 0;
   char16_t unicode;
   nsresult res = NS_OK;
   while (iSrcLength < *aSrcLength )
   {
     unicode = *aSrc;
@@ -212,94 +213,92 @@ NS_IMETHODIMP nsUnicodeToGBK::ConvertNoB
           break;
         }
         aDest[0] = byte1;
         aDest[1] = byte2;
         aDest += 2;	// increment 2 bytes
         iDestLength +=2;
       } else {
         int32_t aOutLen = 2;
-        // make sure we still have 2 bytes for output first
-        if(iDestLength+2 > *aDestLength)
-        {
-          res = NS_OK_UENC_MOREOUTPUT;
-          break;
-        }
         // we cannot map in the common mapping. Let's try to
         // call the delegated 2 byte converter for the gbk or gb18030
         // unique 2 byte mapping
-        if(TryExtensionEncoder(unicode, aDest, &aOutLen))
-        {
+        res = TryExtensionEncoder(unicode, aDest, &aOutLen);
+        if (res == NS_OK) {
           iDestLength += aOutLen;
           aDest += aOutLen;
+        } else if (res == NS_OK_UENC_MOREOUTPUT) {
+          break;
         } else {
-          // make sure we still have 4 bytes for output first
-          if(iDestLength+4 > *aDestLength)
-          {
-            res = NS_OK_UENC_MOREOUTPUT;
-            break;
-          }
           // we still cannot map. Let's try to
-          // call the delegated GB18030 4 byte converter 
+          // call the delegated GB18030 4 byte converter
           aOutLen = 4;
           if( NS_IS_HIGH_SURROGATE(unicode) )
           {
             if((iSrcLength+1) < *aSrcLength ) {
-              if(EncodeSurrogate(aSrc[0],aSrc[1], aDest)) {
+              res = EncodeSurrogate(aSrc[0],aSrc[1], aDest,
+                                    iDestLength, *aDestLength);
+              if (res == NS_OK) {
                 // since we got a surrogate pair, we need to increment src.
-                iSrcLength++ ; 
+                iSrcLength++ ;
                 aSrc++;
                 iDestLength += aOutLen;
                 aDest += aOutLen;
               } else {
-                // only get a high surrogate, but not a low surrogate
-                res = NS_ERROR_UENC_NOMAPPING;
-                iSrcLength++;   // include length of the unmapped character
+                if (res == NS_ERROR_UENC_NOMAPPING) {
+                  // only get a high surrogate, but not a low surrogate
+                  iSrcLength++;   // include length of the unmapped character
+                }
                 break;
               }
             } else {
               mSurrogateHigh = aSrc[0];
+              res = NS_OK;
               break; // this will go to afterwhileloop
             }
           } else {
             if( NS_IS_LOW_SURROGATE(unicode) )
             {
               if(NS_IS_HIGH_SURROGATE(mSurrogateHigh)) {
-                if(EncodeSurrogate(mSurrogateHigh, aSrc[0], aDest)) {
+                res = EncodeSurrogate(mSurrogateHigh, aSrc[0], aDest,
+                                      iDestLength, *aDestLength);
+                if (res == NS_OK) {
                   iDestLength += aOutLen;
                   aDest += aOutLen;
                 } else {
-                  // only get a high surrogate, but not a low surrogate
-                  res = NS_ERROR_UENC_NOMAPPING;
-                  iSrcLength++;   // include length of the unmapped character
+                  if (res == NS_ERROR_UENC_NOMAPPING) {
+                    // only get a high surrogate, but not a low surrogate
+                    iSrcLength++;   // include length of the unmapped character
+                  }
                   break;
                 }
               } else {
                 // only get a low surrogate, but not a low surrogate
                 res = NS_ERROR_UENC_NOMAPPING;
                 iSrcLength++;   // include length of the unmapped character
                 break;
               }
             } else {
-              if(Try4BytesEncoder(unicode, aDest, &aOutLen))
-              {
+              res = Try4BytesEncoder(unicode, aDest, &aOutLen);
+              if (res == NS_OK) {
                 NS_ASSERTION((aOutLen == 4), "we should always generate 4 bytes here");
                 iDestLength += aOutLen;
                 aDest += aOutLen;
               } else {
-                res = NS_ERROR_UENC_NOMAPPING;
-                iSrcLength++;   // include length of the unmapped character
+                if (res == NS_ERROR_UENC_NOMAPPING) {
+                  iSrcLength++;   // include length of the unmapped character
+                }
                 break;
               }
             }
           }
         }
-      } 
+      }
     }
-    iSrcLength++ ; // Each unicode char just count as one in char16_t string;  	  
+    iSrcLength++ ; // Each unicode char just count as one in char16_t string;
     mSurrogateHigh = 0;
     aSrc++;
     if ( iDestLength >= (*aDestLength) && (iSrcLength < *aSrcLength) )
     {
       res = NS_OK_UENC_MOREOUTPUT;
       break;
     }
   }
--- a/intl/uconv/ucvcn/nsUnicodeToGBK.h
+++ b/intl/uconv/ucvcn/nsUnicodeToGBK.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* -*- 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/. */
 
  /**
  * A character set converter from Unicode to GBK.
  * 
  *
@@ -30,45 +30,43 @@ public:
    */
   explicit nsUnicodeToGBK(uint32_t aMaxLengthFactor = 2);
   virtual ~nsUnicodeToGBK() {}
 
 protected:
 
   //--------------------------------------------------------------------
   // Subclassing of nsEncoderSupport class [declaration]
-  NS_IMETHOD ConvertNoBuff(const char16_t * aSrc, 
-                            int32_t * aSrcLength, 
-                            char * aDest, 
-                            int32_t * aDestLength);
-
-  NS_IMETHOD ConvertNoBuffNoErr(const char16_t * aSrc, int32_t * aSrcLength, 
-                                char * aDest, int32_t * aDestLength)
-  {
-    return NS_OK;
-  }  // just make it not abstract;
+  NS_IMETHOD ConvertNoBuffNoErr(const char16_t * aSrc,
+                                int32_t * aSrcLength,
+                                char * aDest,
+                                int32_t * aDestLength);
 
   virtual void CreateExtensionEncoder();
   virtual void Create4BytesEncoder();
 
   nsCOMPtr<nsIUnicodeEncoder> mExtensionEncoder;
   nsCOMPtr<nsIUnicodeEncoder> m4BytesEncoder;
 protected:
   char16_t mSurrogateHigh;
   nsGBKConvUtil mUtil;
-  bool TryExtensionEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
-  bool Try4BytesEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
-  virtual bool EncodeSurrogate(char16_t aSurrogateHigh, char16_t aSurrogateLow, char* aDest);
+  nsresult TryExtensionEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
+  nsresult Try4BytesEncoder(char16_t aChar, char* aDest, int32_t* aOutLen);
+  virtual nsresult EncodeSurrogate(char16_t aSurrogateHigh,
+                                   char16_t aSurrogateLow, char* aDest,
+                                   int32_t aDestLength, int32_t aBufferLength);
 };
 
 class nsUnicodeToGB18030: public nsUnicodeToGBK
 {
 public:
   nsUnicodeToGB18030() : nsUnicodeToGBK(4) {}
   virtual ~nsUnicodeToGB18030() {}
 protected:
   virtual void CreateExtensionEncoder();
   virtual void Create4BytesEncoder();
-  virtual bool EncodeSurrogate(char16_t aSurrogateHigh, char16_t aSurrogateLow, char* aDest);
+  virtual nsresult EncodeSurrogate(char16_t aSurrogateHigh,
+                                   char16_t aSurrogateLow, char* aDest,
+                                   int32_t aDestLength, int32_t aBufferLength);
 };
 
 #endif /* nsUnicodeToGBK_h___ */
 
deleted file mode 100644
--- a/ipc/chromium/src/base/third_party/purify/pure.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Header file of Pure API function declarations.
- *
-* (C) Copyright IBM Corporation. 2006, 2006. All Rights Reserved.
-   *   You may recompile and redistribute these definitions as required.
- *
- * Version 1.0
- */
-
-#if defined(PURIFY) || defined(QUANTIFY)
-
-#if defined(c_plusplus) || defined(__cplusplus)
-extern "C" {
-#endif
-
-// Don't include this file directly, use purify.h instead.
-// If you need something that's not there, add it.
-#ifdef PURIFY_PRIVATE_INCLUDE
-
-#define PURE_H_VERSION 1
-#include <stddef.h>
-
-//////////////////////////////
-// API's Specific to Purify //
-//////////////////////////////
-
-// TRUE when Purify is running.
-int __cdecl PurifyIsRunning(void)			;
-//
-// Print a string to the viewer.
-//
-int __cdecl PurePrintf(const char *fmt, ...)		;
-int __cdecl PurifyPrintf(const char *fmt, ...)		;
-//
-// Purify functions for leak and memory-in-use functionalty.
-//
-size_t __cdecl PurifyNewInuse(void)			;
-size_t __cdecl PurifyAllInuse(void) 			;
-size_t __cdecl PurifyClearInuse(void)			;
-size_t __cdecl PurifyNewLeaks(void)			;
-size_t __cdecl PurifyAllLeaks(void)			;
-size_t __cdecl PurifyClearLeaks(void)			;
-//
-// Purify functions for handle leakage.
-//
-size_t __cdecl PurifyAllHandlesInuse(void)			;
-size_t __cdecl PurifyNewHandlesInuse(void)			;
-//
-// Functions that tell you about the state of memory.
-//
-size_t __cdecl PurifyDescribe(void *addr)			;
-size_t __cdecl PurifyWhatColors(void *addr, size_t size) 	;
-//
-// Functions to test the state of memory.  If the memory is not
-// accessable, an error is signaled just as if there were a memory
-// reference and the function returns false.
-//
-int __cdecl PurifyAssertIsReadable(const void *addr, size_t size)	;	// size used to be an int, until IA64 came along
-int __cdecl PurifyAssertIsWritable(const void *addr, size_t size)	;
-//
-// Functions to test the state of memory.  If the memory is not
-// accessable, these functions return false.  No error is signaled.
-//
-int __cdecl PurifyIsReadable(const void *addr, size_t size)	;
-int __cdecl PurifyIsWritable(const void *addr, size_t size)	;
-int __cdecl PurifyIsInitialized(const void *addr, size_t size)	;
-//
-// Functions to set the state of memory.
-//
-void __cdecl PurifyMarkAsInitialized(void *addr, size_t size)	;
-void __cdecl PurifyMarkAsUninitialized(void *addr, size_t size)	;
-//
-// Functions to do late detection of ABWs, FMWs, IPWs.
-//
-#define PURIFY_HEAP_CRT 					(HANDLE) ~(__int64) 1 /* 0xfffffffe */
-#define PURIFY_HEAP_ALL 					(HANDLE) ~(__int64) 2 /* 0xfffffffd */
-#define PURIFY_HEAP_BLOCKS_LIVE 			0x80000000
-#define PURIFY_HEAP_BLOCKS_DEFERRED_FREE 	0x40000000
-#define PURIFY_HEAP_BLOCKS_ALL 				(PURIFY_HEAP_BLOCKS_LIVE|PURIFY_HEAP_BLOCKS_DEFERRED_FREE)
-int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr)	;
-int __cdecl PurifySetLateDetectScanCounter(int counter);
-int __cdecl PurifySetLateDetectScanInterval(int seconds);
-//
-// Functions to support pool allocators
-//
-void   __cdecl   PurifySetPoolId(const void *mem, int id);
-int	   __cdecl   PurifyGetPoolId(const void *mem);
-void   __cdecl   PurifySetUserData(const void *mem, void *data);
-void * __cdecl   PurifyGetUserData(const void *mem);
-void   __cdecl   PurifyMapPool(int id, void(*fn)());
-
-
-////////////////////////////////
-// API's Specific to Quantify //
-////////////////////////////////
-
-// TRUE when Quantify is running.
-int __cdecl QuantifyIsRunning(void)			;
-
-//
-// Functions for controlling collection
-//
-int __cdecl QuantifyDisableRecordingData(void)		;
-int __cdecl QuantifyStartRecordingData(void)		;
-int __cdecl QuantifyStopRecordingData(void)		;
-int __cdecl QuantifyClearData(void)			;
-int __cdecl QuantifyIsRecordingData(void)		;
-
-// Add a comment to the dataset
-int __cdecl QuantifyAddAnnotation(char *)		;
-
-// Save the current data, creating a "checkpoint" dataset
-int __cdecl QuantifySaveData(void)			;
-
-// Set the name of the current thread in the viewer
-int __cdecl QuantifySetThreadName(char *)		;
-
-////////////////////////////////
-// API's Specific to Coverage //
-////////////////////////////////
-
-// TRUE when Coverage is running.
-int __cdecl CoverageIsRunning(void)			;
-//
-// Functions for controlling collection
-//
-int __cdecl CoverageDisableRecordingData(void)		;
-int __cdecl CoverageStartRecordingData(void)		;
-int __cdecl CoverageStopRecordingData(void)		;
-int __cdecl CoverageClearData(void)			;
-int __cdecl CoverageIsRecordingData(void)		;
-// Add a comment to the dataset
-int __cdecl CoverageAddAnnotation(char *)		;
-
-// Save the current data, creating a "checkpoint" dataset
-int __cdecl CoverageSaveData(void)			;
-
-
-#endif // PURIFY_PRIVATE_INCLUDE
-
-#if defined(c_plusplus) || defined(__cplusplus)
-}
-#endif
-
-#endif // defined(PURIFY) || defined(QUANTIFY)
\ No newline at end of file
deleted file mode 100644
--- a/ipc/chromium/src/base/third_party/purify/pure_api.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Header file of Pure API function declarations.
- *
- * Explicitly no copyright.
- * You may recompile and redistribute these definitions as required.
- *
- * NOTE1: In some situations when compiling with MFC, you should
- *        enable the setting 'Not using precompiled headers' in Visual C++
- *        to avoid a compiler diagnostic.
- *
- * NOTE2: This file works through the use of deep magic.  Calls to functions
- *        in this file are replaced with calls into the OCI runtime system
- *        when an instrumented version of this program is run.
- *
- * NOTE3: The static vars avoidGy_n (where n is a unique number) are used
- *        to prevent optimizing the functions away when compiler option
- *        /Gy is set. This is needed so that NOTE2 works properly.
- */
-
-// Chromium note: We used to only compile this code if PURIFY was defined,
-// because we did special builds with all optimizations turned off for Purify.
-// However, for profiling with Quantify, we want most/all optimizations turned
-// on so that we measure something closer to real execution.
-
-#ifdef _WINDOWS // we only use Purify/Quantify on Windows
-
-#pragma once
- extern int errno;
-typedef int ptrdiff_t;
-typedef unsigned int size_t;
-typedef unsigned short wchar_t;
-static int avoidGy_1 = 0;
-static int avoidGy_2 = 0;
-static int avoidGy_3 = 0;
-static int avoidGy_4 = 0;
-static int avoidGy_5 = 0;
-static int avoidGy_6 = 0;
-static int avoidGy_7 = 0;
-static int avoidGy_8 = 0;
-static int avoidGy_9 = 0;
-static int avoidGy_10 = 0;
-static int avoidGy_11 = 0;
-static int avoidGy_12 = 0;
-static int avoidGy_13 = 0;
-static int avoidGy_14 = 0;
-static int avoidGy_15 = 0;
-static int avoidGy_16 = 0;
-static int avoidGy_17 = 0;
-static int avoidGy_18 = 0;
-static int avoidGy_19 = 0;
-static int avoidGy_20 = 0;
-static int avoidGy_21 = 0;
-static int avoidGy_22 = 0;
-static int avoidGy_23 = 0;
-static int avoidGy_24 = 0;
-static int avoidGy_25 = 0;
-static int avoidGy_26 = 0;
-static int avoidGy_27 = 0;
-static int avoidGy_28 = 0;
-static int avoidGy_29 = 0;
-static int avoidGy_30 = 0;
-static int avoidGy_31 = 0;
-static int avoidGy_32 = 0;
-static int avoidGy_33 = 0;
-static int avoidGy_34 = 0;
-static int avoidGy_35 = 0;
-static int avoidGy_36 = 0;
-static int avoidGy_37 = 0;
-static int avoidGy_38 = 0;
-static int avoidGy_39 = 0;
-static int avoidGy_40 = 0;
-static int avoidGy_41 = 0;
-static int avoidGy_42 = 0;
-static int avoidGy_43 = 0;
-static int avoidGy_44 = 0;
-static int avoidGy_45 = 0;
-static int avoidGy_46 = 0;
-static int avoidGy_47 = 0;
-static int avoidGy_48 = 0;
-static int avoidGy_49 = 0;
-static int avoidGy_50 = 0;
-static int avoidGy_51 = 0;
-static int avoidGy_52 = 0;
-static int avoidGy_53 = 0;
-static int avoidGy_54 = 0;
-static int avoidGy_55 = 0;
-static int avoidGy_56 = 0;
-static int avoidGy_57 = 0;
-static int avoidGy_58 = 0;
-static int avoidGy_59 = 0;
-static int avoidGy_60 = 0;
-static int avoidGy_61 = 0;
-static int avoidGy_62 = 0;
-static int avoidGy_63 = 0;
-static int avoidGy_64 = 0;
-static int avoidGy_65 = 0;
-static int avoidGy_PL_01 = 0;
-static int avoidGy_PL_02 = 0;
-__declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { if(!++avoidGy_1); fmt; return 0; }
-__declspec(dllexport) int __cdecl PurifyIsRunning(void) { if(!++avoidGy_2); return 0; }
-__declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { if(!++avoidGy_3); fmt; return 0; }
-__declspec(dllexport) size_t __cdecl PurifyNewInuse(void) { if(!++avoidGy_4); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyAllInuse(void) { if(!++avoidGy_5); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyClearInuse(void) { if(!++avoidGy_6); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyNewLeaks(void) { if(!++avoidGy_7); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyAllLeaks(void) { if(!++avoidGy_8); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyClearLeaks(void) { if(!++avoidGy_9); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyAllHandlesInuse(void) { if(!++avoidGy_10); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyNewHandlesInuse(void) { if(!++avoidGy_11); return 0; }
-__declspec(dllexport) size_t __cdecl PurifyDescribe(void *addr) { if(!++avoidGy_12); addr; return 0; }
-__declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, size_t size) { if(!++avoidGy_13); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, size_t size) { if(!++avoidGy_14); addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, size_t size) { if(!++avoidGy_15); addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, size_t size) { if(!++avoidGy_16); addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, size_t size) { if(!++avoidGy_17); addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, size_t size) { if(!++avoidGy_18); addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyRed(void *addr, size_t size) { if(!++avoidGy_19); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyGreen(void *addr, size_t size) { if(!++avoidGy_20); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyYellow(void *addr, size_t size) { if(!++avoidGy_21); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyBlue(void *addr, size_t size) { if(!++avoidGy_22); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, size_t size) { if(!++avoidGy_23); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, size_t size) { if(!++avoidGy_24); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, size_t size) { if(!++avoidGy_25); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, size_t size) { if(!++avoidGy_26); addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) 
- { if(!++avoidGy_27); hHeap; dwFlags; addr; return 1; }
-__declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { if(!++avoidGy_28); counter; return 0; };
-__declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { if(!++avoidGy_29); seconds; return 0; };
-__declspec(dllexport) void __cdecl PurifySetPoolId(const void *mem, int id) { if(!++avoidGy_61); mem; id; return; };
-__declspec(dllexport) int __cdecl PurifyGetPoolId(const void *mem) { if(!++avoidGy_62); mem; return 0; };
-__declspec(dllexport) void __cdecl PurifySetUserData(const void *mem, void *data) { if(!++avoidGy_63); mem; data; return; };
-__declspec(dllexport) void * __cdecl PurifyGetUserData(const void *mem) { if(!++avoidGy_64); mem; return 0; };
-__declspec(dllexport) void __cdecl PurifyMapPool(int id, void(*fn)()) { if(!++avoidGy_65); id; fn; return; };
-__declspec(dllexport) int __cdecl CoverageIsRunning(void) { if(!++avoidGy_30); return 0; }
-__declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { if(!++avoidGy_31); return 0; }
-__declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { if(!++avoidGy_32); return 0; }
-__declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { if(!++avoidGy_33); return 0; }
-__declspec(dllexport) int __cdecl CoverageClearData(void) { if(!++avoidGy_34); return 0; }
-__declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { if(!++avoidGy_35); return 0; }
-__declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { if(!++avoidGy_36); str; return 0; }
-__declspec(dllexport) int __cdecl CoverageSaveData(void) { if(!++avoidGy_37); return 0; }
-__declspec(dllexport) int __cdecl QuantifyIsRunning(void) { if(!++avoidGy_42); return 0; }
-__declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { if(!++avoidGy_43); return 0; }
-__declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { if(!++avoidGy_44); return 0; }
-__declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { if(!++avoidGy_45); return 0; }
-__declspec(dllexport) int __cdecl QuantifyClearData(void) { if(!++avoidGy_46); return 0; }
-__declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { if(!++avoidGy_47); return 0; }
-__declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { if(!++avoidGy_48); str; return 0; }
-__declspec(dllexport) int __cdecl QuantifySaveData(void) { if(!++avoidGy_49); return 0; }
-__declspec(dllexport) int __cdecl QuantifySetThreadName(const char *szName) { if(!++avoidGy_50) ; szName; return 0; }
-
-#endif // _WINDOWS
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -142,17 +142,17 @@ public:
   {
     mNeckoParent = aNeckoParent;
   }
 
   NeckoParent* GetNeckoParent() { return mNeckoParent; }
 };
 
 template<class ListenerT>
-class /*NS_INTERFACE_CLASS*/ IProtocolManager
+class IProtocolManager
 {
 public:
     enum ActorDestroyReason {
         FailedConstructor,
         Deletion,
         AncestorDeletion,
         NormalShutdown,
         AbnormalShutdown
--- a/ipc/ipdl/ipdl/cxx/cgen.py
+++ b/ipc/ipdl/ipdl/cxx/cgen.py
@@ -120,27 +120,21 @@ class CxxCodeGen(CodePrinter, Visitor):
         self.visitDecl(p)
         if p.default is not None:
             self.write(' = ')
             p.default.accept(self)
 
     def visitClass(self, c):
         if c.specializes is not None:
             self.printdentln('template<>')
-        
+
         if c.struct:
             self.printdent('struct')
         else:
             self.printdent('class')
-        if c.interface:
-            # FIXME/cjones: turn this "on" when we get the analysis
-            self.write(' /*NS_INTERFACE_CLASS*/')
-        if c.abstract:
-            # FIXME/cjones: turn this "on" when we get the analysis
-            self.write(' /*NS_ABSTRACT_CLASS*/')
         self.write(' '+ c.name)
         if c.final:
             self.write(' final')
 
         if c.specializes is not None:
             self.write(' <')
             c.specializes.accept(self)
             self.write('>')
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1170355.js
@@ -0,0 +1,3 @@
+x = Array(4294967295);
+x[1] = 0;
+Array.prototype.shift.call(x);
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -320,24 +320,29 @@ VirtualRegister::setInitialDefinition(Co
 {
     LiveRange* first = LiveRange::get(*rangesBegin());
     MOZ_ASSERT(from >= first->from());
     first->setFrom(from);
     first->setHasDefinition();
 }
 
 LiveRange*
-VirtualRegister::rangeFor(CodePosition pos) const
+VirtualRegister::rangeFor(CodePosition pos, bool preferRegister /* = false */) const
 {
+    LiveRange* found = nullptr;
     for (LiveRange::RegisterLinkIterator iter = rangesBegin(); iter; iter++) {
         LiveRange* range = LiveRange::get(*iter);
-        if (range->covers(pos))
-            return range;
+        if (range->covers(pos)) {
+            if (!preferRegister || range->bundle()->allocation().isRegister())
+                return range;
+            if (!found)
+                found = range;
+        }
     }
-    return nullptr;
+    return found;
 }
 
 void
 VirtualRegister::addRange(LiveRange* range)
 {
     InsertSortedList(ranges_, &range->registerLink);
 }
 
@@ -1701,17 +1706,17 @@ BacktrackingAllocator::resolveControlFlo
                 {
                     skip = true;
                     break;
                 }
             }
             if (skip)
                 continue;
 
-            LiveRange* predecessorRange = reg.rangeFor(start.previous());
+            LiveRange* predecessorRange = reg.rangeFor(start.previous(), /* preferRegister = */ true);
             if (start.subpos() == CodePosition::INPUT) {
                 if (!moveInput(ins->toInstruction(), predecessorRange, range, reg.type()))
                     return false;
             } else {
                 if (!moveAfter(ins->toInstruction(), predecessorRange, range, reg.type()))
                     return false;
             }
         }
@@ -1737,17 +1742,17 @@ BacktrackingAllocator::resolveControlFlo
             LiveRange* to = reg.rangeFor(entryOf(successor));
             MOZ_ASSERT(to);
 
             for (size_t k = 0; k < mSuccessor->numPredecessors(); k++) {
                 LBlock* predecessor = mSuccessor->getPredecessor(k)->lir();
                 MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
 
                 LAllocation* input = phi->getOperand(k);
-                LiveRange* from = vreg(input).rangeFor(exitOf(predecessor));
+                LiveRange* from = vreg(input).rangeFor(exitOf(predecessor), /* preferRegister = */ true);
                 MOZ_ASSERT(from);
 
                 if (!moveAtExit(predecessor, from, to, def->type()))
                     return false;
             }
         }
 
         // Add moves to resolve graph edges with different allocations at their
@@ -1762,17 +1767,17 @@ BacktrackingAllocator::resolveControlFlo
 
                 for (LiveRange::RegisterLinkIterator iter = reg.rangesBegin(); iter; iter++) {
                     LiveRange* to = LiveRange::get(*iter);
                     if (!to->covers(entryOf(successor)))
                         continue;
                     if (to->covers(exitOf(predecessor)))
                         continue;
 
-                    LiveRange* from = reg.rangeFor(exitOf(predecessor));
+                    LiveRange* from = reg.rangeFor(exitOf(predecessor), /* preferRegister = */ true);
 
                     if (mSuccessor->numPredecessors() > 1) {
                         MOZ_ASSERT(predecessor->mir()->numSuccessors() == 1);
                         if (!moveAtExit(predecessor, from, to, reg.type()))
                             return false;
                     } else {
                         if (!moveAtEntry(successor, from, to, reg.type()))
                             return false;
@@ -2321,21 +2326,22 @@ bool
 BacktrackingAllocator::minimalDef(LiveRange* range, LNode* ins)
 {
     // Whether this is a minimal range capturing a definition at ins.
     return (range->to() <= minimalDefEnd(ins).next()) &&
            ((!ins->isPhi() && range->from() == inputOf(ins)) || range->from() == outputOf(ins));
 }
 
 bool
-BacktrackingAllocator::minimalUse(LiveRange* range, LNode* ins)
+BacktrackingAllocator::minimalUse(LiveRange* range, UsePosition* use)
 {
-    // Whether this is a minimal range capturing a use at ins.
+    // Whether this is a minimal range capturing |use|.
+    LNode* ins = insData[use->pos];
     return (range->from() == inputOf(ins)) &&
-           (range->to() == outputOf(ins) || range->to() == outputOf(ins).next());
+           (range->to() == (use->use->usedAtStart() ? outputOf(ins) : outputOf(ins).next()));
 }
 
 bool
 BacktrackingAllocator::minimalBundle(LiveBundle* bundle, bool* pfixed)
 {
     LiveRange::BundleLinkIterator iter = bundle->rangesBegin();
     LiveRange* range = LiveRange::get(*iter);
 
@@ -2363,22 +2369,22 @@ BacktrackingAllocator::minimalBundle(Liv
             multiple = true;
         LUse* use = iter->use;
 
         switch (use->policy()) {
           case LUse::FIXED:
             if (fixed)
                 return false;
             fixed = true;
-            if (minimalUse(range, insData[iter->pos]))
+            if (minimalUse(range, *iter))
                 minimal = true;
             break;
 
           case LUse::REGISTER:
-            if (minimalUse(range, insData[iter->pos]))
+            if (minimalUse(range, *iter))
                 minimal = true;
             break;
 
           default:
             break;
         }
     }
 
--- a/js/src/jit/BacktrackingAllocator.h
+++ b/js/src/jit/BacktrackingAllocator.h
@@ -519,17 +519,17 @@ class VirtualRegister
         return !!rangesBegin();
     }
     LiveRange* firstRange() const {
         return LiveRange::get(*rangesBegin());
     }
     LiveRange* lastRange() const {
         return LiveRange::get(ranges_.back());
     }
-    LiveRange* rangeFor(CodePosition pos) const;
+    LiveRange* rangeFor(CodePosition pos, bool preferRegister = false) const;
     void removeRange(LiveRange* range);
     void addRange(LiveRange* range);
 
     LiveBundle* firstBundle() const {
         return firstRange()->bundle();
     }
 
     bool addInitialRange(TempAllocator& alloc, CodePosition from, CodePosition to);
@@ -702,17 +702,17 @@ class BacktrackingAllocator : protected 
 
     // Debugging methods.
     void dumpFixedRanges();
     void dumpAllocations();
 
     struct PrintLiveRange;
 
     bool minimalDef(LiveRange* range, LNode* ins);
-    bool minimalUse(LiveRange* range, LNode* ins);
+    bool minimalUse(LiveRange* range, UsePosition* use);
     bool minimalBundle(LiveBundle* bundle, bool* pfixed = nullptr);
 
     // Heuristic methods.
 
     size_t computePriority(LiveBundle* bundle);
     size_t computeSpillWeight(LiveBundle* bundle);
 
     size_t maximumSpillWeight(const LiveBundleVector& bundles);
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2203,18 +2203,24 @@ CodeGenerator::visitMoveGroup(LMoveGroup
         }
 
         masm.propagateOOM(resolver.addMove(toMoveOperand(from), toMoveOperand(to), moveType));
     }
 
     masm.propagateOOM(resolver.resolve());
 
     MoveEmitter emitter(masm);
+
+#ifdef JS_CODEGEN_X86
     if (group->maybeScratchRegister().isGeneralReg())
         emitter.setScratchRegister(group->maybeScratchRegister().toGeneralReg()->reg());
+    else
+        resolver.sortMemoryToMemoryMoves();
+#endif
+
     emitter.emit(resolver);
     emitter.finish();
 }
 
 void
 CodeGenerator::visitInteger(LInteger* lir)
 {
     masm.move32(Imm32(lir->getValue()), ToRegister(lir->output()));
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -114,24 +114,20 @@ class LMoveGroup : public LInstructionHe
     const LMove& getMove(size_t i) const {
         return moves_[i];
     }
 
 #ifdef JS_CODEGEN_X86
     void setScratchRegister(Register reg) {
         scratchRegister_ = LGeneralReg(reg);
     }
-#endif
     LAllocation maybeScratchRegister() {
-#ifdef JS_CODEGEN_X86
         return scratchRegister_;
-#else
-        return LAllocation();
+    }
 #endif
-    }
 
     bool uses(Register reg) {
         for (size_t i = 0; i < numMoves(); i++) {
             LMove move = getMove(i);
             if (move.from() == LGeneralReg(reg) || move.to() == LGeneralReg(reg))
                 return true;
         }
         return false;
--- a/js/src/jit/MoveResolver.cpp
+++ b/js/src/jit/MoveResolver.cpp
@@ -196,19 +196,95 @@ MoveResolver::addOrderedMove(const MoveO
                 return orderedMoves_.insert(after, nmove);
             } else if (move.to().isGeneralReg() || move.to().isFloatReg()) {
                 MoveOp nmove(move.to(), existing.to(), move.type());
                 orderedMoves_[i] = move;
                 return orderedMoves_.insert(after, nmove);
             }
         }
 
-        if (existing.to().aliases(move.from()) ||
-            existing.to().aliases(move.to()) ||
-            existing.from().aliases(move.to()) ||
-            existing.from().aliases(move.from()))
-        {
+        if (existing.aliases(move))
             break;
-        }
     }
 
     return orderedMoves_.append(move);
 }
+
+void
+MoveResolver::reorderMove(size_t from, size_t to)
+{
+    MOZ_ASSERT(from != to);
+
+    MoveOp op = orderedMoves_[from];
+    if (from < to) {
+        for (size_t i = from; i < to; i++)
+            orderedMoves_[i] = orderedMoves_[i + 1];
+    } else {
+        for (size_t i = from; i > to; i--)
+            orderedMoves_[i] = orderedMoves_[i - 1];
+    }
+    orderedMoves_[to] = op;
+}
+
+void
+MoveResolver::sortMemoryToMemoryMoves()
+{
+    // Try to reorder memory->memory moves so that they are executed right
+    // before a move that clobbers some register. This will allow the move
+    // emitter to use that clobbered register as a scratch register for the
+    // memory->memory move, if necessary.
+    for (size_t i = 0; i < orderedMoves_.length(); i++) {
+        const MoveOp& base = orderedMoves_[i];
+        if (!base.from().isMemory() || !base.to().isMemory())
+            continue;
+        if (base.type() != MoveOp::GENERAL && base.type() != MoveOp::INT32)
+            continue;
+
+        // Look for an earlier move clobbering a register.
+        bool found = false;
+        for (int j = i - 1; j >= 0; j--) {
+            const MoveOp& previous = orderedMoves_[j];
+            if (previous.aliases(base) || previous.isCycleBegin() || previous.isCycleEnd())
+                break;
+
+            if (previous.to().isGeneralReg()) {
+                reorderMove(i, j);
+                found = true;
+                break;
+            }
+        }
+        if (found)
+            continue;
+
+        // Look for a later move clobbering a register.
+        if (i + 1 < orderedMoves_.length()) {
+            bool found = false, skippedRegisterUse = false;
+            for (size_t j = i + 1; j < orderedMoves_.length(); j++) {
+                const MoveOp& later = orderedMoves_[j];
+                if (later.aliases(base) || later.isCycleBegin() || later.isCycleEnd())
+                    break;
+
+                if (later.to().isGeneralReg()) {
+                    if (skippedRegisterUse) {
+                        reorderMove(i, j);
+                        found = true;
+                    } else {
+                        // There is no move that uses a register between the
+                        // original memory->memory move and this move that
+                        // clobbers a register. The move should already be able
+                        // to use a scratch register, so don't shift anything
+                        // around.
+                    }
+                    break;
+                }
+
+                if (later.from().isGeneralReg())
+                    skippedRegisterUse = true;
+            }
+
+            if (found) {
+                // Redo the search for memory->memory moves at the current
+                // index, so we don't skip the move just shifted back.
+                i--;
+            }
+        }
+    }
+}
--- a/js/src/jit/MoveResolver.h
+++ b/js/src/jit/MoveResolver.h
@@ -192,16 +192,22 @@ class MoveOp
     }
     Type type() const {
         return type_;
     }
     Type endCycleType() const {
         MOZ_ASSERT(isCycleBegin());
         return endCycleType_;
     }
+    bool aliases(const MoveOperand& op) const {
+        return from().aliases(op) || to().aliases(op);
+    }
+    bool aliases(const MoveOp& other) const {
+        return aliases(other.from()) || aliases(other.to());
+    }
 };
 
 class MoveResolver
 {
   private:
     struct PendingMove
       : public MoveOp,
         public TempObject,
@@ -224,44 +230,44 @@ class MoveResolver
             cycleEnd_ = true;
             cycleEndSlot_ = cycleSlot;
         }
     };
 
     typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator;
 
   private:
-    // Moves that are definitely unblocked (constants to registers). These are
-    // emitted last.
     js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_;
     int numCycles_;
     int curCycles_;
     TempObjectPool<PendingMove> movePool_;
 
     InlineList<PendingMove> pending_;
 
     PendingMove* findBlockingMove(const PendingMove* last);
     PendingMove* findCycledMove(PendingMoveIterator* stack, PendingMoveIterator end, const PendingMove* first);
     bool addOrderedMove(const MoveOp& move);
+    void reorderMove(size_t from, size_t to);
 
     // Internal reset function. Does not clear lists.
     void resetState();
 
   public:
     MoveResolver();
 
     // Resolves a move group into two lists of ordered moves. These moves must
     // be executed in the order provided. Some moves may indicate that they
     // participate in a cycle. For every cycle there are two such moves, and it
     // is guaranteed that cycles do not nest inside each other in the list.
     //
     // After calling addMove() for each parallel move, resolve() performs the
     // cycle resolution algorithm. Calling addMove() again resets the resolver.
     bool addMove(const MoveOperand& from, const MoveOperand& to, MoveOp::Type type);
     bool resolve();
+    void sortMemoryToMemoryMoves();
 
     size_t numMoves() const {
         return orderedMoves_.length();
     }
     const MoveOp& getMove(size_t i) const {
         return orderedMoves_[i];
     }
     uint32_t numCycles() const {
--- a/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MoveEmitter-x86-shared.cpp
@@ -6,16 +6,18 @@
 
 #include "jit/x86-shared/MoveEmitter-x86-shared.h"
 
 #include "jit/MacroAssembler-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Maybe;
+
 MoveEmitterX86::MoveEmitterX86(MacroAssembler& masm)
   : inCycle_(false),
     masm(masm),
     pushedAtCycle_(-1)
 {
     pushedAtStart_ = masm.framePushed();
 }
 
@@ -96,21 +98,29 @@ MoveEmitterX86::maybeEmitOptimizedCycle(
     return false;
 }
 
 void
 MoveEmitterX86::emit(const MoveResolver& moves)
 {
 #if defined(JS_CODEGEN_X86) && defined(DEBUG)
     // Clobber any scratch register we have, to make regalloc bugs more visible.
-    if (hasScratchRegister())
-        masm.mov(ImmWord(0xdeadbeef), scratchRegister());
+    if (scratchRegister_.isSome())
+        masm.mov(ImmWord(0xdeadbeef), scratchRegister_.value());
 #endif
 
     for (size_t i = 0; i < moves.numMoves(); i++) {
+#if defined(JS_CODEGEN_X86) && defined(DEBUG)
+        if (!scratchRegister_.isSome()) {
+            Maybe<Register> reg = findScratchRegister(moves, i);
+            if (reg.isSome())
+                masm.mov(ImmWord(0xdeadbeef), reg.value());
+        }
+#endif
+
         const MoveOp& move = moves.getMove(i);
         const MoveOperand& from = move.from();
         const MoveOperand& to = move.to();
 
         if (move.isCycleEnd()) {
             MOZ_ASSERT(inCycle_);
             completeCycle(to, move.type());
             inCycle_ = false;
@@ -139,20 +149,20 @@ MoveEmitterX86::emit(const MoveResolver&
         switch (move.type()) {
           case MoveOp::FLOAT32:
             emitFloat32Move(from, to);
             break;
           case MoveOp::DOUBLE:
             emitDoubleMove(from, to);
             break;
           case MoveOp::INT32:
-            emitInt32Move(from, to);
+            emitInt32Move(from, to, moves, i);
             break;
           case MoveOp::GENERAL:
-            emitGeneralMove(from, to);
+            emitGeneralMove(from, to, moves, i);
             break;
           case MoveOp::INT32X4:
             emitInt32X4Move(from, to);
             break;
           case MoveOp::FLOAT32X4:
             emitFloat32X4Move(from, to);
             break;
           default:
@@ -358,67 +368,69 @@ MoveEmitterX86::completeCycle(const Move
         masm.Pop(toPopOperand(to));
         break;
       default:
         MOZ_CRASH("Unexpected move type");
     }
 }
 
 void
-MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to)
+MoveEmitterX86::emitInt32Move(const MoveOperand& from, const MoveOperand& to,
+                              const MoveResolver& moves, size_t i)
 {
     if (from.isGeneralReg()) {
         masm.move32(from.reg(), toOperand(to));
     } else if (to.isGeneralReg()) {
         MOZ_ASSERT(from.isMemory());
         masm.load32(toAddress(from), to.reg());
     } else {
         // Memory to memory gpr move.
         MOZ_ASSERT(from.isMemory());
-        if (hasScratchRegister()) {
-            Register reg = scratchRegister();
-            masm.load32(toAddress(from), reg);
-            masm.move32(reg, toOperand(to));
+        Maybe<Register> reg = findScratchRegister(moves, i);
+        if (reg.isSome()) {
+            masm.load32(toAddress(from), reg.value());
+            masm.move32(reg.value(), toOperand(to));
         } else {
             // No scratch register available; bounce it off the stack.
             masm.Push(toOperand(from));
             masm.Pop(toPopOperand(to));
         }
     }
 }
 
 void
-MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to)
+MoveEmitterX86::emitGeneralMove(const MoveOperand& from, const MoveOperand& to,
+                                const MoveResolver& moves, size_t i)
 {
     if (from.isGeneralReg()) {
         masm.mov(from.reg(), toOperand(to));
     } else if (to.isGeneralReg()) {
         MOZ_ASSERT(from.isMemoryOrEffectiveAddress());
         if (from.isMemory())
             masm.loadPtr(toAddress(from), to.reg());
         else
             masm.lea(toOperand(from), to.reg());
     } else if (from.isMemory()) {
         // Memory to memory gpr move.
-        if (hasScratchRegister()) {
-            Register reg = scratchRegister();
-            masm.loadPtr(toAddress(from), reg);
-            masm.mov(reg, toOperand(to));
+        Maybe<Register> reg = findScratchRegister(moves, i);
+        if (reg.isSome()) {
+            masm.loadPtr(toAddress(from), reg.value());
+            masm.mov(reg.value(), toOperand(to));
         } else {
             // No scratch register available; bounce it off the stack.
             masm.Push(toOperand(from));
             masm.Pop(toPopOperand(to));
         }
     } else {
         // Effective address to memory move.
         MOZ_ASSERT(from.isEffectiveAddress());
-        if (hasScratchRegister()) {
-            Register reg = scratchRegister();
-            masm.lea(toOperand(from), reg);
-            masm.mov(reg, toOperand(to));
+        Maybe<Register> reg = findScratchRegister(moves, i);
+        if (reg.isSome()) {
+            masm.lea(toOperand(from), reg.value());
+            masm.mov(reg.value(), toOperand(to));
         } else {
             // This is tricky without a scratch reg. We can't do an lea. Bounce the
             // base register off the stack, then add the offset in place. Note that
             // this clobbers FLAGS!
             masm.Push(from.base());
             masm.Pop(toPopOperand(to));
             masm.addPtr(Imm32(from.disp()), toOperand(to));
         }
@@ -518,8 +530,39 @@ MoveEmitterX86::assertDone()
 void
 MoveEmitterX86::finish()
 {
     assertDone();
 
     masm.freeStack(masm.framePushed() - pushedAtStart_);
 }
 
+Maybe<Register>
+MoveEmitterX86::findScratchRegister(const MoveResolver& moves, size_t initial)
+{
+#ifdef JS_CODEGEN_X86
+    if (scratchRegister_.isSome())
+        return scratchRegister_;
+
+    // All registers are either in use by this move group or are live
+    // afterwards. Look through the remaining moves for a register which is
+    // clobbered before it is used, and is thus dead at this point.
+    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
+    for (size_t i = initial; i < moves.numMoves(); i++) {
+        const MoveOp& move = moves.getMove(i);
+        if (move.from().isGeneralReg())
+            regs.takeUnchecked(move.from().reg());
+        else if (move.from().isMemoryOrEffectiveAddress())
+            regs.takeUnchecked(move.from().base());
+        if (move.to().isGeneralReg()) {
+            if (i != initial && !move.isCycleBegin() && regs.has(move.to().reg()))
+                return mozilla::Some(move.to().reg());
+            regs.takeUnchecked(move.to().reg());
+        } else if (move.to().isMemoryOrEffectiveAddress()) {
+            regs.takeUnchecked(move.to().base());
+        }
+    }
+
+    return mozilla::Nothing();
+#else
+    return mozilla::Some(ScratchReg);
+#endif
+}
--- a/js/src/jit/x86-shared/MoveEmitter-x86-shared.h
+++ b/js/src/jit/x86-shared/MoveEmitter-x86-shared.h
@@ -35,18 +35,20 @@ class MoveEmitterX86
     Address toAddress(const MoveOperand& operand) const;
     Operand toOperand(const MoveOperand& operand) const;
     Operand toPopOperand(const MoveOperand& operand) const;
 
     size_t characterizeCycle(const MoveResolver& moves, size_t i,
                              bool* allGeneralRegs, bool* allFloatRegs);
     bool maybeEmitOptimizedCycle(const MoveResolver& moves, size_t i,
                                  bool allGeneralRegs, bool allFloatRegs, size_t swapCount);
-    void emitInt32Move(const MoveOperand& from, const MoveOperand& to);
-    void emitGeneralMove(const MoveOperand& from, const MoveOperand& to);
+    void emitInt32Move(const MoveOperand& from, const MoveOperand& to,
+                       const MoveResolver& moves, size_t i);
+    void emitGeneralMove(const MoveOperand& from, const MoveOperand& to,
+                         const MoveResolver& moves, size_t i);
     void emitFloat32Move(const MoveOperand& from, const MoveOperand& to);
     void emitDoubleMove(const MoveOperand& from, const MoveOperand& to);
     void emitFloat32X4Move(const MoveOperand& from, const MoveOperand& to);
     void emitInt32X4Move(const MoveOperand& from, const MoveOperand& to);
     void breakCycle(const MoveOperand& to, MoveOp::Type type);
     void completeCycle(const MoveOperand& to, MoveOp::Type type);
 
   public:
@@ -56,32 +58,17 @@ class MoveEmitterX86
     void finish();
 
     void setScratchRegister(Register reg) {
 #ifdef JS_CODEGEN_X86
         scratchRegister_.emplace(reg);
 #endif
     }
 
-    bool hasScratchRegister() {
-#ifdef JS_CODEGEN_X86
-        return scratchRegister_.isSome();
-#else
-        return true;
-#endif
-    }
-
-    Register scratchRegister() {
-        MOZ_ASSERT(hasScratchRegister());
-#ifdef JS_CODEGEN_X86
-        return scratchRegister_.value();
-#else
-        return ScratchReg;
-#endif
-    }
+    mozilla::Maybe<Register> findScratchRegister(const MoveResolver& moves, size_t i);
 };
 
 typedef MoveEmitterX86 MoveEmitter;
 
 } // ion
 } // js
 
 #endif /* jit_MoveEmitter_x86_shared_h */
--- a/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp
+++ b/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp
@@ -44,57 +44,57 @@ BEGIN_TEST(testDefinePropertyIgnoredAttr
 
     // Try a getter. Allow it to fill in the defaults. Because we're passing a
     // JSNative, JS_DefineProperty will infer JSPROP_GETTER even though we
     // aren't passing it.
     CHECK(JS_DefineProperty(cx, obj, "foo", defineValue,
                             JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT | JSPROP_SHARED,
                             Getter));
 
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "foo", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "foo", &desc));
 
     // Note that JSPROP_READONLY is meaningless for accessor properties.
     CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, false));
 
     // Install another configurable property, so we can futz with it.
     CHECK(JS_DefineProperty(cx, obj, "bar", defineValue,
                             JSPROP_IGNORE_ENUMERATE | JSPROP_SHARED,
                             Getter));
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "bar", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
     CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, true));
 
     // Rewrite the descriptor to now be enumerable, leaving the configurability
     // unchanged.
     CHECK(JS_DefineProperty(cx, obj, "bar", defineValue,
                             JSPROP_IGNORE_PERMANENT | JSPROP_ENUMERATE | JSPROP_SHARED,
                             Getter));
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "bar", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc));
     CHECK(CheckDescriptor(desc, AccessorDescriptor, true, true, true));
 
     // Now try the same game with a value property
     defineValue.setObject(*obj);
     CHECK(JS_DefineProperty(cx, obj, "baz", defineValue,
                             JSPROP_IGNORE_ENUMERATE |
                             JSPROP_IGNORE_READONLY |
                             JSPROP_IGNORE_PERMANENT));
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "baz", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "baz", &desc));
     CHECK(CheckDescriptor(desc, DataDescriptor, false, false, false));
 
     // Now again with a configurable property
     CHECK(JS_DefineProperty(cx, obj, "quux", defineValue,
                             JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY));
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "quux", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc));
     CHECK(CheckDescriptor(desc, DataDescriptor, false, false, true));
 
     // Just make it writable. Leave the old value and everything else alone.
     defineValue.setUndefined();
     CHECK(JS_DefineProperty(cx, obj, "quux", defineValue,
                             JSPROP_IGNORE_ENUMERATE |
                             JSPROP_IGNORE_PERMANENT |
                             JSPROP_IGNORE_VALUE));
 
-    CHECK(JS_GetPropertyDescriptor(cx, obj, "quux", &desc));
+    CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc));
     CHECK(CheckDescriptor(desc, DataDescriptor, false, true, true));
     CHECK_SAME(JS::ObjectValue(*obj), desc.value());
 
     return true;
 }
 END_TEST(testDefinePropertyIgnoredAttributes)
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -2164,17 +2164,20 @@ js::array_shift(JSContext* cx, unsigned 
     DenseElementResult result = CallBoxedOrUnboxedSpecialization(functor, obj);
     if (result != DenseElementResult::Incomplete) {
         if (result == DenseElementResult::Failure)
             return false;
 
         if (!SetLengthProperty(cx, obj, newlen))
             return false;
 
-        return SuppressDeletedProperty(cx, obj, INT_TO_JSID(newlen));
+        RootedId id(cx);
+        if (!IndexToId(cx, newlen, &id))
+            return false;
+        return SuppressDeletedProperty(cx, obj, id);
     }
 
     /* Steps 5, 10. */
     bool hole;
     if (!GetElement(cx, obj, uint32_t(0), &hole, args.rval()))
         return false;
 
     /* Steps 6-7. */
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Class/newTargetNonFunction.js
@@ -0,0 +1,10 @@
+// Make sure that we can plumb new.target, even if the results are going to
+// throw.
+
+assertThrowsInstanceOf(() => new ""(...Array()), TypeError);
+
+assertThrowsInstanceOf(() => new ""(), TypeError);
+assertThrowsInstanceOf(() => new ""(1), TypeError);
+
+if (typeof reportCompare === 'function')
+    reportCompare(0,0,"OK");
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -4582,20 +4582,18 @@ js::SpreadCallOperation(JSContext* cx, H
         return false;
 
     args.setCallee(callee);
     args.setThis(thisv);
 
     if (!GetElements(cx, aobj, length, args.array()))
         return false;
 
-    if (constructing) {
-        MOZ_ASSERT(newTarget.isObject());
+    if (constructing)
         args.newTarget().set(newTarget);
-    }
 
     switch (op) {
       case JSOP_SPREADNEW:
         if (!InvokeConstructor(cx, args))
             return false;
         break;
       case JSOP_SPREADCALL:
         if (!Invoke(cx, args))
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -1256,35 +1256,43 @@ nsGridContainerFrame::ReflowChildren(Gri
     if (MOZ_LIKELY(isGridItem)) {
       GridArea* area = GetGridAreaForChild(child);
       MOZ_ASSERT(area && area->IsDefinite());
       cb = ContainingBlockFor(wm, *area, aColSizes, aRowSizes);
       cb += gridOrigin;
     } else {
       cb = aContentArea;
     }
-    nsHTMLReflowState childRS(pc, aReflowState, child, cb.Size(wm));
+    WritingMode childWM = child->GetWritingMode();
+    LogicalSize childCBSize = cb.Size(wm).ConvertTo(childWM, wm);
+    nsHTMLReflowState childRS(pc, aReflowState, child, childCBSize);
     const LogicalMargin margin = childRS.ComputedLogicalMargin();
     if (childRS.ComputedBSize() == NS_AUTOHEIGHT && MOZ_LIKELY(isGridItem)) {
       // XXX the start of an align-self:stretch impl.  Needs min-/max-bsize
       // clamping though, and check the prop value is actually 'stretch'!
       LogicalMargin bp = childRS.ComputedLogicalBorderPadding();
       bp.ApplySkipSides(child->GetLogicalSkipSides());
-      nscoord bSize = cb.BSize(wm) - bp.BStartEnd(wm) - margin.BStartEnd(wm);
+      nscoord bSize = childCBSize.BSize(childWM) - bp.BStartEnd(childWM) -
+                        margin.BStartEnd(childWM);
       childRS.SetComputedBSize(std::max(bSize, 0));
     }
-    LogicalPoint childPos = cb.Origin(wm);
-    childPos.I(wm) += margin.IStart(wm);
-    childPos.B(wm) += margin.BStart(wm);
+    // We need the width of the child before we can correctly convert
+    // the writing-mode of its origin, so we reflow at (0, 0) and then
+    // pass the correct position to FinishReflowChild.
     nsHTMLReflowMetrics childSize(childRS);
     nsReflowStatus childStatus;
-    ReflowChild(child, pc, childSize, childRS, wm, childPos,
-                containerWidth, 0, childStatus);
+    ReflowChild(child, pc, childSize, childRS, childWM, LogicalPoint(childWM),
+                0, 0, childStatus);
+    LogicalPoint childPos =
+      cb.Origin(wm).ConvertTo(childWM, wm, containerWidth - childSize.Width() -
+                                           margin.LeftRight(childWM));
+    childPos.I(childWM) += margin.IStart(childWM);
+    childPos.B(childWM) += margin.BStart(childWM);
     childRS.ApplyRelativePositioning(&childPos, containerWidth);
-    FinishReflowChild(child, pc, childSize, &childRS, wm, childPos,
+    FinishReflowChild(child, pc, childSize, &childRS, childWM, childPos,
                       containerWidth, 0);
     ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
     // XXX deal with 'childStatus' not being COMPLETE
   }
 
   if (IsAbsoluteContainer()) {
     nsFrameList children(GetChildList(GetAbsoluteListID()));
     if (!children.IsEmpty()) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-dir-001-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<style type="text/css">
+.grid {
+  border: 1px solid gray;
+  font-size: 0;
+}
+.grid > div {
+  display: inline-block;
+  margin: 2px;
+}
+#a { background: #006; height: 46px; width: 96px; }
+#b { background: #009; height: 46px; width: 146px; }
+#c { background: #00c; height: 46px; width: 46px; }
+#d { background: #00f; height: 46px; width: 16px; }
+#e { background: #060; height: 96px; width: 96px; }
+#f { background: #090; height: 96px; width: 146px; }
+#g { background: #0c0; height: 96px; width: 46px; }
+#h { background: #0f0; height: 96px; width: 16px; }
+#i { background: #600; height: 16px; width: 96px; }
+#j { background: #900; height: 16px; width: 146px; }
+#k { background: #c00; height: 16px; width: 46px; }
+#l { background: #f00; height: 16px; width: 16px; }
+</style>
+</head>
+
+<body>
+<div class=grid>
+  <div id=a></div>
+  <div id=b></div>
+  <div id=c></div>
+  <div id=d></div><br>
+  <div id=e></div>
+  <div id=f></div>
+  <div id=g></div>
+  <div id=h></div><br>
+  <div id=i></div>
+  <div id=j></div>
+  <div id=k></div>
+  <div id=l></div>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-grid/grid-item-dir-001.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="utf-8">
+<style type="text/css">
+.grid {
+  display: grid;
+  border: 1px solid gray;
+  grid-template-columns: 100px 150px 50px 20px;
+  grid-template-rows: 50px 100px 20px;
+}
+.grid > div {
+  margin: 2px;
+}
+#a { background: #006; }
+#b { background: #009; }
+#c { background: #00c; }
+#d { background: #00f; }
+#e { background: #060; }
+#f { background: #090; }
+#g { background: #0c0; }
+#h { background: #0f0; }
+#i { background: #600; }
+#j { background: #900; }
+#k { background: #c00; }
+#l { background: #f00; }
+</style>
+</head>
+
+<body>
+<div class=grid>
+  <div id=a></div>
+  <div id=b></div>
+  <div id=c></div>
+  <div id=d></div>
+  <div id=e dir=rtl></div>
+  <div id=f dir=rtl></div>
+  <div id=g dir=rtl></div>
+  <div id=h dir=rtl></div>
+  <div id=i></div>
+  <div id=j dir=rtl></div>
+  <div id=k></div>
+  <div id=l dir=rtl></div>
+</div>
+</body>
+</html>
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -20,8 +20,9 @@ skip-if(Android) == grid-placement-defin
 == grid-placement-definite-implicit-002.html grid-placement-definite-implicit-002-ref.html
 skip-if(Android) == grid-placement-auto-implicit-001.html grid-placement-auto-implicit-001-ref.html
 == grid-placement-abspos-implicit-001.html grid-placement-abspos-implicit-001-ref.html
 pref(layout.css.vertical-text.enabled,true) == rtl-grid-placement-definite-001.html rtl-grid-placement-definite-001-ref.html
 pref(layout.css.vertical-text.enabled,true) == rtl-grid-placement-auto-row-sparse-001.html rtl-grid-placement-auto-row-sparse-001-ref.html
 pref(layout.css.vertical-text.enabled,true) == vlr-grid-placement-auto-row-sparse-001.html vlr-grid-placement-auto-row-sparse-001-ref.html
 pref(layout.css.vertical-text.enabled,true) == vrl-grid-placement-auto-row-sparse-001.html vrl-grid-placement-auto-row-sparse-001-ref.html
 == grid-relpos-items-001.html grid-relpos-items-001-ref.html
+== grid-item-dir-001.html grid-item-dir-001-ref.html
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -238,17 +238,21 @@ ErrorReporter::AddToError(const nsString
   if (mError.IsEmpty()) {
     mError = aErrorText;
     mErrorLineNumber = mScanner->GetLineNumber();
     mErrorColNumber = mScanner->GetColumnNumber();
     // Retrieve the error line once per line, and reuse the same nsString
     // for all errors on that line.  That causes the text of the line to
     // be shared among all the nsIScriptError objects.
     if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
-      mErrorLine = mScanner->GetCurrentLine();
+      // Be careful here: the error line might be really long and OOM
+      // when we try to make a copy here.  If so, just leave it empty.
+      if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
+        mErrorLine.Truncate();
+      }
       mPrevErrorLineNumber = mErrorLineNumber;
     }
   } else {
     mError.AppendLiteral("  ");
     mError.Append(aErrorText);
   }
 }
 
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -154,46 +154,43 @@ nsTableFrame::nsTableFrame(nsStyleContex
 }
 
 void
 nsTableFrame::Init(nsIContent*       aContent,
                    nsContainerFrame* aParent,
                    nsIFrame*         aPrevInFlow)
 {
   NS_PRECONDITION(!mCellMap, "Init called twice");
+  NS_PRECONDITION(!mTableLayoutStrategy, "Init called twice");
   NS_PRECONDITION(!aPrevInFlow ||
                   aPrevInFlow->GetType() == nsGkAtoms::tableFrame,
                   "prev-in-flow must be of same type");
 
   // Let the base class do its processing
   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   // see if border collapse is on, if so set it
   const nsStyleTableBorder* tableStyle = StyleTableBorder();
   bool borderCollapse = (NS_STYLE_BORDER_COLLAPSE == tableStyle->mBorderCollapse);
   SetBorderCollapse(borderCollapse);
 
-  // Create the cell map if this frame is the first-in-flow.
   if (!aPrevInFlow) {
+    // If we're the first-in-flow, we manage the cell map & layout strategy that
+    // get used by our continuation chain:
     mCellMap = new nsTableCellMap(*this, borderCollapse);
-  }
-
-  if (aPrevInFlow) {
+    if (IsAutoLayout()) {
+      mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
+    } else {
+      mTableLayoutStrategy = new FixedTableLayoutStrategy(this);
+    }
+  } else {
     // set my width, because all frames in a table flow are the same width and
     // code in nsTableOuterFrame depends on this being set
     mRect.width = aPrevInFlow->GetSize().width;
   }
-  else {
-    NS_ASSERTION(!mTableLayoutStrategy, "strategy was created before Init was called");
-    // create the strategy
-    if (IsAutoLayout())
-      mTableLayoutStrategy = new BasicTableLayoutStrategy(this);
-    else
-      mTableLayoutStrategy = new FixedTableLayoutStrategy(this);
-  }
 }
 
 nsTableFrame::~nsTableFrame()
 {
   delete mCellMap;
   delete mTableLayoutStrategy;
 }
 
@@ -300,18 +297,17 @@ nsTableFrame::UnregisterPositionedTableP
   tableFrame = static_cast<nsTableFrame*>(tableFrame->FirstContinuation());
 
   // Retrieve the positioned parts array for this table.
   FrameProperties props = tableFrame->Properties();
   auto positionedParts =
     static_cast<FrameTArray*>(props.Get(PositionedTablePartArray()));
 
   // Remove the frame.
-  MOZ_ASSERT(positionedParts &&
-             positionedParts->IndexOf(aFrame) != FrameTArray::NoIndex,
+  MOZ_ASSERT(positionedParts && positionedParts->Contains(aFrame),
              "Asked to unregister a positioned table part that wasn't registered");
   if (positionedParts) {
     positionedParts->RemoveElement(aFrame);
   }
 }
 
 // XXX this needs to be cleaned up so that the frame constructor breaks out col group
 // frames into a separate child list, bug 343048.
@@ -1787,17 +1783,17 @@ nsTableFrame::Reflow(nsPresContext*     
 {
   MarkInReflow();
   DO_GLOBAL_REFLOW_COUNT("nsTableFrame");
   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   bool isPaginated = aPresContext->IsPaginated();
 
   aStatus = NS_FRAME_COMPLETE;
   if (!GetPrevInFlow() && !mTableLayoutStrategy) {
-    NS_ASSERTION(false, "strategy should have been created in Init");
+    NS_ERROR("strategy should have been created in Init");
     return;
   }
 
   // see if collapsing borders need to be calculated
   if (!GetPrevInFlow() && IsBorderCollapse() && NeedToCalcBCBorders()) {
     CalcBCBorders();
   }
 
@@ -1887,17 +1883,17 @@ nsTableFrame::Reflow(nsPresContext*     
       }
       haveDesiredHeight = true;
 
       mutable_rs.mFlags.mSpecialHeightReflow = false;
     }
   }
   else {
     // Calculate the overflow area contribution from our children.
-    for (nsIFrame* kid = GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) {
+    for (nsIFrame* kid : mFrames) {
       ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kid);
     }
   }
 
   aDesiredSize.Width() = aReflowState.ComputedWidth() +
                        aReflowState.ComputedPhysicalBorderPadding().LeftRight();
   if (!haveDesiredHeight) {
     CalcDesiredHeight(aReflowState, aDesiredSize);
@@ -2046,17 +2042,17 @@ nsTableFrame::ReflowTable(nsHTMLReflowMe
 }
 
 nsIFrame*
 nsTableFrame::GetFirstBodyRowGroupFrame()
 {
   nsIFrame* headerFrame = nullptr;
   nsIFrame* footerFrame = nullptr;
 
-  for (nsIFrame* kidFrame = mFrames.FirstChild(); nullptr != kidFrame; ) {
+  for (nsIFrame* kidFrame : mFrames) {
     const nsStyleDisplay* childDisplay = kidFrame->StyleDisplay();
 
     // We expect the header and footer row group frames to be first, and we only
     // allow one header and one footer
     if (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == childDisplay->mDisplay) {
       if (headerFrame) {
         // We already have a header frame and so this header frame is treated
         // like an ordinary body row group frame
@@ -2070,19 +2066,16 @@ nsTableFrame::GetFirstBodyRowGroupFrame(
         // like an ordinary body row group frame
         return kidFrame;
       }
       footerFrame = kidFrame;
 
     } else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) {
       return kidFrame;
     }
-
-    // Get the next child
-    kidFrame = kidFrame->GetNextSibling();
   }
 
   return nullptr;
 }
 
 // Table specific version that takes into account repeated header and footer
 // frames when continuing table frames
 void
@@ -2165,18 +2158,17 @@ nsTableFrame::AdjustForCollapsingRowsCol
 
 
 nscoord
 nsTableFrame::GetCollapsedWidth(nsMargin aBorderPadding)
 {
   NS_ASSERTION(!GetPrevInFlow(), "GetCollapsedWidth called on next in flow");
   nscoord width = GetColSpacing(GetColCount());
   width += aBorderPadding.left + aBorderPadding.right;
-  for (nsIFrame* groupFrame = mColGroups.FirstChild(); groupFrame;
-         groupFrame = groupFrame->GetNextSibling()) {
+  for (nsIFrame* groupFrame : mColGroups) {
     const nsStyleVisibility* groupVis = groupFrame->StyleVisibility();
     bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
     nsTableColGroupFrame* cgFrame = (nsTableColGroupFrame*)groupFrame;
     for (nsTableColFrame* colFrame = cgFrame->GetFirstColumn(); colFrame;
          colFrame = colFrame->GetNextCol()) {
       const nsStyleDisplay* colDisplay = colFrame->StyleDisplay();
       int32_t colX = colFrame->GetColIndex();
       if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) {
@@ -3195,18 +3187,17 @@ nsTableFrame::ReflowChildren(nsTableRefl
 }
 
 void
 nsTableFrame::ReflowColGroups(nsRenderingContext *aRenderingContext)
 {
   if (!GetPrevInFlow() && !HaveReflowedColGroups()) {
     nsHTMLReflowMetrics kidMet(GetWritingMode());
     nsPresContext *presContext = PresContext();
-    for (nsIFrame* kidFrame = mColGroups.FirstChild(); kidFrame;
-         kidFrame = kidFrame->GetNextSibling()) {
+    for (nsIFrame* kidFrame : mColGroups) {
       if (NS_SUBTREE_DIRTY(kidFrame)) {
         // The column groups don't care about dimensions or reflow states.
         nsHTMLReflowState
           kidReflowState(presContext, kidFrame, aRenderingContext,
                          LogicalSize(kidFrame->GetWritingMode()));
         nsReflowStatus cgStatus;
         ReflowChild(kidFrame, presContext, kidMet, kidReflowState, 0, 0, 0,
                     cgStatus);
@@ -3218,17 +3209,17 @@ nsTableFrame::ReflowColGroups(nsRenderin
 }
 
 void
 nsTableFrame::CalcDesiredHeight(const nsHTMLReflowState& aReflowState,
                                 nsHTMLReflowMetrics& aDesiredSize)
 {
   nsTableCellMap* cellMap = GetCellMap();
   if (!cellMap) {
-    NS_ASSERTION(false, "never ever call me until the cell map is built!");
+    NS_ERROR("never ever call me until the cell map is built!");
     aDesiredSize.Height() = 0;
     return;
   }
   nsMargin borderPadding = GetChildAreaOffset(&aReflowState);
 
   // get the natural height based on the last child's (row group) rect
   RowGroupArray rowGroups;
   OrderRowGroups(rowGroups);
@@ -3262,17 +3253,17 @@ nsTableFrame::CalcDesiredHeight(const ns
     nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState);
     if ((tableSpecifiedHeight > 0) &&
         (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE) &&
         (tableSpecifiedHeight > desiredHeight)) {
       // proportionately distribute the excess height to unconstrained rows in each
       // unconstrained row group.
       DistributeHeightToRows(aReflowState, tableSpecifiedHeight - desiredHeight);
       // this might have changed the overflow area incorporate the childframe overflow area.
-      for (nsIFrame* kidFrame = mFrames.FirstChild(); kidFrame; kidFrame = kidFrame->GetNextSibling()) {
+      for (nsIFrame* kidFrame : mFrames) {
         ConsiderChildOverflow(aDesiredSize.mOverflowAreas, kidFrame);
       }
       desiredHeight = tableSpecifiedHeight;
     }
   }
   aDesiredSize.Height() = desiredHeight;
 }
 
@@ -3870,18 +3861,17 @@ nsTableFrame::Dump(bool            aDump
         printf(" anonymous-colgroup ");
         break;
       case eColAnonymousCell:
         printf(" anonymous-cell ");
         break;
       }
     }
     printf("\n colgroups->");
-    for (nsIFrame* childFrame = mColGroups.FirstChild(); childFrame;
-         childFrame = childFrame->GetNextSibling()) {
+    for (nsIFrame* childFrame : mColGroups) {
       if (nsGkAtoms::tableColGroupFrame == childFrame->GetType()) {
         nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame *)childFrame;
         colGroupFrame->Dump(1);
       }
     }
     for (colX = 0; colX < numCols; colX++) {
       printf("\n");
       nsTableColFrame* colFrame = GetColFrame(colX);
@@ -4402,17 +4392,17 @@ BCMapCellInfo::SetInfo(nsTableRowFrame* 
     mEndRow = mStartRow->GetNextRow();
     if (mEndRow) {
       for (int32_t span = 2; mEndRow && span < mRowSpan; span++) {
         mEndRow = mEndRow->GetNextRow();
       }
       NS_ASSERTION(mEndRow, "spanned row not found");
     }
     else {
-      NS_ASSERTION(false, "error in cell map");
+      NS_ERROR("error in cell map");
       mRowSpan = 1;
       mEndRow = mStartRow;
     }
   }
   // row group frame info
   // try to reuse the rgStart and rgEnd from the iterator as calls to
   // GetRowCount() are computationally expensive and should be avoided if
   // possible
@@ -6991,17 +6981,17 @@ BCVerticalSeg::Paint(BCPaintBorderIterat
       NS_ERROR("a neighboring rowgroup can never own a vertical border");
       // and fall through
     case eRowGroupOwner:
       NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
                   "row group can own border only at table edge");
       owner = mFirstRowGroup;
       break;
     case eAjaRowOwner:
-      NS_ASSERTION(false, "program error"); // and fall through
+      NS_ERROR("program error"); // and fall through
     case eRowOwner:
       NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
                    "row can own border only at table edge");
       owner = mFirstRow;
       break;
     case eAjaCellOwner:
       side = eLogicalSideIEnd;
       cell = mAjaCell; // and fall through
--- a/media/mtransport/databuffer.h
+++ b/media/mtransport/databuffer.h
@@ -12,38 +12,63 @@
 #include <mozilla/UniquePtr.h>
 #include <m_cpp_utils.h>
 #include <nsISupportsImpl.h>
 
 namespace mozilla {
 
 class DataBuffer {
  public:
-  DataBuffer() : data_(nullptr), len_(0) {}
+  DataBuffer() : data_(nullptr), len_(0), capacity_(0) {}
   DataBuffer(const uint8_t *data, size_t len) {
-    Assign(data, len);
+    Assign(data, len, len);
+  }
+  DataBuffer(const uint8_t *data, size_t len, size_t capacity) {
+    Assign(data, len, capacity);
+  }
+
+  // to ensure extra space for expansion
+  void Assign(const uint8_t *data, size_t len, size_t capacity) {
+    MOZ_RELEASE_ASSERT(len <= capacity);
+    Allocate(capacity); // sets len_ = capacity
+    memcpy(static_cast<void *>(data_.get()),
+           static_cast<const void *>(data), len);
+    len_ = len;
   }
 
-  void Assign(const uint8_t *data, size_t len) {
-    Allocate(len);
-    memcpy(static_cast<void *>(data_.get()),
-           static_cast<const void *>(data), len);
+  void Allocate(size_t capacity) {
+    data_.reset(new uint8_t[capacity ? capacity : 1]);  // Don't depend on new [0].
+    len_ = capacity_ = capacity;
   }
 
-  void Allocate(size_t len) {
-    data_.reset(new uint8_t[len ? len : 1]);  // Don't depend on new [0].
+  void EnsureCapacity(size_t capacity) {
+    if (capacity_ < capacity) {
+      uint8_t *new_data = new uint8_t[ capacity ? capacity : 1];
+      memcpy(static_cast<void *>(new_data),
+             static_cast<const void *>(data_.get()), len_);
+      data_.reset(new_data); // after copying!  Deletes old data
+      capacity_ = capacity;
+    }
+  }
+
+  // used when something writes to the buffer (having checked
+  // capacity() or used EnsureCapacity()) and increased the length.
+  void SetLength(size_t len) {
+    MOZ_RELEASE_ASSERT(len <= capacity_);
     len_ = len;
   }
 
   const uint8_t *data() const { return data_.get(); }
   uint8_t *data() { return data_.get(); }
   size_t len() const { return len_; }
+  size_t capacity() const { return capacity_; }
 
 private:
   UniquePtr<uint8_t[]> data_;
   size_t len_;
+  size_t capacity_;
 
   DISALLOW_COPY_ASSIGN(DataBuffer);
 };
 
 }
 
 #endif
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.cpp
@@ -64,17 +64,16 @@ WebrtcAudioConduit::~WebrtcAudioConduit(
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   for(std::vector<AudioCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
   {
     delete mRecvCodecList[i];
   }
-  delete mCurSendCodecConfig;
 
   // The first one of a pair to be deleted shuts down media for both
   if(mPtrVoEXmedia)
   {
     mPtrVoEXmedia->SetExternalRecordingStatus(false);
     mPtrVoEXmedia->SetExternalPlayoutStatus(false);
   }
 
@@ -355,20 +354,22 @@ WebrtcAudioConduit::SetReceiverTransport
 MediaConduitErrorCode
 WebrtcAudioConduit::ConfigureSendMediaCodec(const AudioCodecConfig* codecConfig)
 {
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   MediaConduitErrorCode condError = kMediaConduitNoError;
   int error = 0;//webrtc engine errors
   webrtc::CodecInst cinst;
 
-  //validate codec param
-  if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
   {
-    return condError;
+    //validate codec param
+    if((condError = ValidateCodecConfig(codecConfig, true)) != kMediaConduitNoError)
+    {
+      return condError;
+    }
   }
 
   condError = StopTransmitting();
   if (condError != kMediaConduitNoError) {
     return condError;
   }
 
   if(!CodecConfigToWebRTCCodec(codecConfig,cinst))
@@ -406,26 +407,27 @@ WebrtcAudioConduit::ConfigureSendMediaCo
   }
 #endif
 
   condError = StartTransmitting();
   if (condError != kMediaConduitNoError) {
     return condError;
   }
 
-  //Copy the applied config for future reference.
-  delete mCurSendCodecConfig;
+  {
+    MutexAutoLock lock(mCodecMutex);
 
-  mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
-                                              codecConfig->mName,
-                                              codecConfig->mFreq,
-                                              codecConfig->mPacSize,
-                                              codecConfig->mChannels,
-                                              codecConfig->mRate);
-
+    //Copy the applied config for future reference.
+    mCurSendCodecConfig = new AudioCodecConfig(codecConfig->mType,
+                                               codecConfig->mName,
+                                               codecConfig->mFreq,
+                                               codecConfig->mPacSize,
+                                               codecConfig->mChannels,
+                                               codecConfig->mRate);
+  }
   return kMediaConduitNoError;
 }
 
 MediaConduitErrorCode
 WebrtcAudioConduit::ConfigureRecvMediaCodecs(
                     const std::vector<AudioCodecConfig*>& codecConfigList)
 {
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
@@ -1013,17 +1015,17 @@ WebrtcAudioConduit::CheckCodecForMatch(c
 
 
 /**
  * Perform validation on the codecConfig to be applied.
  * Verifies if the codec is already applied.
  */
 MediaConduitErrorCode
 WebrtcAudioConduit::ValidateCodecConfig(const AudioCodecConfig* codecInfo,
-                                        bool send) const
+                                        bool send)
 {
   bool codecAppliedAlready = false;
 
   if(!codecInfo)
   {
     CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
@@ -1040,16 +1042,18 @@ WebrtcAudioConduit::ValidateCodecConfig(
   {
     CSFLogError(logTag, "%s Channel Unsupported ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
   //check if we have the same codec already applied
   if(send)
   {
+    MutexAutoLock lock(mCodecMutex);
+
     codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
   } else {
     codecAppliedAlready = CheckCodecForMatch(codecInfo);
   }
 
   if(codecAppliedAlready)
   {
     CSFLogDebug(logTag, "%s Codec %s Already Applied  ", __FUNCTION__, codecInfo->mName.c_str());
--- a/media/webrtc/signaling/src/media-conduit/AudioConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/AudioConduit.h
@@ -164,17 +164,17 @@ public:
   WebrtcAudioConduit():
                       mVoiceEngine(nullptr),
                       mTransportMonitor("WebrtcAudioConduit"),
                       mTransmitterTransport(nullptr),
                       mReceiverTransport(nullptr),
                       mEngineTransmitting(false),
                       mEngineReceiving(false),
                       mChannel(-1),
-                      mCurSendCodecConfig(nullptr),
+                      mCodecMutex("AudioConduit codec db"),
                       mCaptureDelay(150),
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
                       mLastTimestamp(0),
 #endif // MOZILLA_INTERNAL_API
                       mSamples(0),
                       mLastSyncLog(0)
   {
   }
@@ -240,17 +240,17 @@ private:
   bool CopyCodecToDB(const AudioCodecConfig* codecInfo);
 
   // Functions to verify if the codec passed is already in
   // conduits database
   bool CheckCodecForMatch(const AudioCodecConfig* codecInfo) const;
   bool CheckCodecsForMatch(const AudioCodecConfig* curCodecConfig,
                            const AudioCodecConfig* codecInfo) const;
   //Checks the codec to be applied
-  MediaConduitErrorCode ValidateCodecConfig(const AudioCodecConfig* codecInfo, bool send) const;
+  MediaConduitErrorCode ValidateCodecConfig(const AudioCodecConfig* codecInfo, bool send);
 
   //Utility function to dump recv codec database
   void DumpCodecDB() const;
 
   webrtc::VoiceEngine* mVoiceEngine;
   mozilla::ReentrantMonitor mTransportMonitor;
   mozilla::RefPtr<TransportInterface> mTransmitterTransport;
   mozilla::RefPtr<TransportInterface> mReceiverTransport;
@@ -272,17 +272,19 @@ private:
   struct Processing {
     TimeStamp mTimeStamp;
     uint32_t mRTPTimeStamp; // RTP timestamps received
   };
   nsAutoTArray<Processing,8> mProcessing;
 
   int mChannel;
   RecvCodecList    mRecvCodecList;
-  AudioCodecConfig* mCurSendCodecConfig;
+
+  Mutex mCodecMutex; // protects mCurSendCodecConfig
+  nsAutoPtr<AudioCodecConfig> mCurSendCodecConfig;
 
   // Current "capture" delay (really output plus input delay)
   int32_t mCaptureDelay;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   uint32_t mLastTimestamp;
 #endif // MOZILLA_INTERNAL_API
 
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.cpp
@@ -69,17 +69,17 @@ WebrtcVideoConduit::WebrtcVideoConduit()
   mTransmitterTransport(nullptr),
   mReceiverTransport(nullptr),
   mRenderer(nullptr),
   mPtrExtCapture(nullptr),
   mEngineTransmitting(false),
   mEngineReceiving(false),
   mChannel(-1),
   mCapId(-1),
-  mCurSendCodecConfig(nullptr),
+  mCodecMutex("VideoConduit codec db"),
   mSendingWidth(0),
   mSendingHeight(0),
   mReceivingWidth(640),
   mReceivingHeight(480),
   mSendingFramerate(DEFAULT_VIDEO_MAX_FRAMERATE),
   mLastFramerateTenths(DEFAULT_VIDEO_MAX_FRAMERATE*10),
   mNumReceivingStreams(1),
   mVideoLatencyTestEnable(false),
@@ -96,18 +96,16 @@ WebrtcVideoConduit::~WebrtcVideoConduit(
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
 
   for(std::vector<VideoCodecConfig*>::size_type i=0;i < mRecvCodecList.size();i++)
   {
     delete mRecvCodecList[i];
   }
 
-  delete mCurSendCodecConfig;
-
   // The first one of a pair to be deleted shuts down media for both
   //Deal with External Capturer
   if(mPtrViECapture)
   {
     mPtrViECapture->DisconnectCaptureDevice(mCapId);
     mPtrViECapture->ReleaseCaptureDevice(mCapId);
     mPtrExtCapture = nullptr;
   }
@@ -231,18 +229,19 @@ bool WebrtcVideoConduit::GetVideoEncoder
   // we could use a lock.  Note that we don't change it often, and read it once per frame.
   // We scale by *10 because mozilla::Atomic<> doesn't do 'double' or 'float'.
   double framerate = mLastFramerateTenths/10.0; // fetch once
   if (std::abs(*framerateMean - framerate)/framerate > 0.1 &&
       *framerateMean >= 0.5) {
     // unchanged resolution, but adjust bandwidth limits to match camera fps
     CSFLogDebug(logTag, "Encoder frame rate changed from %f to %f",
                 (mLastFramerateTenths/10.0), *framerateMean);
+    MutexAutoLock lock(mCodecMutex);
     mLastFramerateTenths = *framerateMean * 10;
-    SelectSendResolution(mSendingWidth, mSendingHeight, true);
+    SelectSendResolution(mSendingWidth, mSendingHeight);
   }
   return true;
 }
 
 bool WebrtcVideoConduit::GetVideoDecoderStats(double* framerateMean,
                                               double* framerateStdDev,
                                               double* bitrateMean,
                                               double* bitrateStdDev,
@@ -590,39 +589,41 @@ WebrtcVideoConduit::ConfigureCodecMode(w
 {
   CSFLogDebug(logTag,  "%s ", __FUNCTION__);
   mCodecMode = mode;
   return kMediaConduitNoError;
 }
 /**
  * Note: Setting the send-codec on the Video Engine will restart the encoder,
  * sets up new SSRC and reset RTP_RTCP module with the new codec setting.
+ *
+ * Note: this is called from MainThread, and the codec settings are read on
+ * videoframe delivery threads (i.e in SendVideoFrame().  With
+ * renegotiation/reconfiguration, this now needs a lock!  Alternatively
+ * changes could be queued until the next frame is delivered using an
+ * Atomic pointer and swaps.
  */
 MediaConduitErrorCode
 WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
 {
   CSFLogDebug(logTag,  "%s for %s", __FUNCTION__, codecConfig ? codecConfig->mName.c_str() : "<null>");
   bool codecFound = false;
   MediaConduitErrorCode condError = kMediaConduitNoError;
   int error = 0; //webrtc engine errors
   webrtc::VideoCodec  video_codec;
   std::string payloadName;
 
   memset(&video_codec, 0, sizeof(video_codec));
 
-  //validate basic params
-  if((condError = ValidateCodecConfig(codecConfig,true)) != kMediaConduitNoError)
   {
-    return condError;
-  }
-
-  //Check if we have same codec already applied
-  if(CheckCodecsForMatch(mCurSendCodecConfig, codecConfig))
-  {
-    CSFLogDebug(logTag,  "%s Codec has been applied already ", __FUNCTION__);
+    //validate basic params
+    if((condError = ValidateCodecConfig(codecConfig,true)) != kMediaConduitNoError)
+    {
+      return condError;
+    }
   }
 
   condError = StopTransmitting();
   if (condError != kMediaConduitNoError) {
     return condError;
   }
 
   if (mExternalSendCodec &&
@@ -704,20 +705,22 @@ WebrtcVideoConduit::ConfigureSendMediaCo
     }
   }
 
   condError = StartTransmitting();
   if (condError != kMediaConduitNoError) {
     return condError;
   }
 
-  //Copy the applied config for future reference.
-  delete mCurSendCodecConfig;
+  {
+    MutexAutoLock lock(mCodecMutex);
 
-  mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
+    //Copy the applied config for future reference.
+    mCurSendCodecConfig = new VideoCodecConfig(*codecConfig);
+  }
 
   mPtrRTP->SetRembStatus(mChannel, true, false);
 
   return kMediaConduitNoError;
 }
 
 MediaConduitErrorCode
 WebrtcVideoConduit::ConfigureRecvMediaCodecs(
@@ -992,21 +995,22 @@ WebrtcVideoConduit::SelectBandwidth(webr
     // Mostly this would be ultra-low-light situations/mobile or screensharing.
     vie_codec.minBitrate = vie_codec.minBitrate * ((10-(framerate/2))/30);
     vie_codec.maxBitrate = vie_codec.maxBitrate * ((10-(framerate/2))/30);
   }
 }
 
 // XXX we need to figure out how to feed back changes in preferred capture
 // resolution to the getUserMedia source
+// Invoked under lock of mCodecMutex!
 bool
 WebrtcVideoConduit::SelectSendResolution(unsigned short width,
-                                         unsigned short height,
-                                         bool force)
+                                         unsigned short height)
 {
+  mCodecMutex.AssertCurrentThreadOwns();
   // XXX This will do bandwidth-resolution adaptation as well - bug 877954
 
   // Limit resolution to max-fs while keeping same aspect ratio as the
   // incoming image.
   if (mCurSendCodecConfig && mCurSendCodecConfig->mMaxFrameSize)
   {
     unsigned int cur_fs, max_width, max_height, mb_width, mb_height, mb_max;
 
@@ -1066,102 +1070,94 @@ WebrtcVideoConduit::SelectSendResolution
 
     // Favor even multiples of pixels for width and height.
     width = std::max(width & ~1, 2);
     height = std::max(height & ~1, 2);
   }
 
   // Adapt to getUserMedia resolution changes
   // check if we need to reconfigure the sending resolution.
-  // force tells us to do it regardless, such as when the FPS changes
-  if (mSendingWidth != width || mSendingHeight != height || force)
+  bool changed = false;
+  if (mSendingWidth != width || mSendingHeight != height)
   {
     // This will avoid us continually retrying this operation if it fails.
     // If the resolution changes, we'll try again.  In the meantime, we'll
     // keep using the old size in the encoder.
     mSendingWidth = width;
     mSendingHeight = height;
+    changed = true;
+  }
 
+  // uses mSendingWidth/Height
+  unsigned int framerate = SelectSendFrameRate(mSendingFramerate);
+  if (mSendingFramerate != framerate) {
+    mSendingFramerate = framerate;
+    changed = true;
+  }
+
+  if (changed) {
     // Get current vie codec.
     webrtc::VideoCodec vie_codec;
     int32_t err;
 
     if ((err = mPtrViECodec->GetSendCodec(mChannel, vie_codec)) != 0)
     {
       CSFLogError(logTag, "%s: GetSendCodec failed, err %d", __FUNCTION__, err);
       return false;
     }
-    if (vie_codec.width != width || vie_codec.height != height || force)
+    // Likely spurious unless there was some error, but rarely checked
+    if (vie_codec.width != width || vie_codec.height != height ||
+        vie_codec.maxFramerate != mSendingFramerate)
     {
       vie_codec.width = width;
       vie_codec.height = height;
+      vie_codec.maxFramerate = mSendingFramerate;
       SelectBandwidth(vie_codec, width, height);
 
       if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0)
       {
         CSFLogError(logTag, "%s: SetSendCodec(%ux%u) failed, err %d",
                     __FUNCTION__, width, height, err);
         return false;
       }
-      CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u, bitrate %u:%u",
-                  __FUNCTION__, width, height,
+      CSFLogDebug(logTag, "%s: Encoder resolution changed to %ux%u @ %ufps, bitrate %u:%u",
+                  __FUNCTION__, width, height, mSendingFramerate,
                   vie_codec.minBitrate, vie_codec.maxBitrate);
     } // else no change; mSendingWidth likely was 0
   }
   return true;
 }
-// TODO(ruil2@cisco.com):combine SelectSendResolution with SelectSendFrameRate Bug 1132318
-bool
-WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate)
+
+// Invoked under lock of mCodecMutex!
+unsigned int
+WebrtcVideoConduit::SelectSendFrameRate(unsigned int framerate) const
 {
+  mCodecMutex.AssertCurrentThreadOwns();
+  unsigned int new_framerate = framerate;
+
   // Limit frame rate based on max-mbps
-  mSendingFramerate = framerate;
   if (mCurSendCodecConfig && mCurSendCodecConfig->mMaxMBPS)
   {
     unsigned int cur_fs, mb_width, mb_height, max_fps;
 
     mb_width = (mSendingWidth + 15) >> 4;
     mb_height = (mSendingHeight + 15) >> 4;
 
     cur_fs = mb_width * mb_height;
     max_fps = mCurSendCodecConfig->mMaxMBPS/cur_fs;
     if (max_fps < mSendingFramerate) {
-      mSendingFramerate = max_fps;
+      new_framerate = max_fps;
     }
 
     if (mCurSendCodecConfig->mMaxFrameRate != 0 &&
       mCurSendCodecConfig->mMaxFrameRate < mSendingFramerate) {
-      mSendingFramerate = mCurSendCodecConfig->mMaxFrameRate;
+      new_framerate = mCurSendCodecConfig->mMaxFrameRate;
     }
   }
-  if (mSendingFramerate != framerate)
-  {
-    // Get current vie codec.
-    webrtc::VideoCodec vie_codec;
-    int32_t err;
-
-    if ((err = mPtrViECodec->GetSendCodec(mChannel, vie_codec)) != 0)
-    {
-      CSFLogError(logTag, "%s: GetSendCodec failed, err %d", __FUNCTION__, err);
-      return false;
-    }
-    if (vie_codec.maxFramerate != mSendingFramerate)
-    {
-      vie_codec.maxFramerate = mSendingFramerate;
-      if ((err = mPtrViECodec->SetSendCodec(mChannel, vie_codec)) != 0)
-      {
-        CSFLogError(logTag, "%s: SetSendCodec(%u) failed, err %d",
-                       __FUNCTION__, mSendingFramerate, err);
-        return false;
-      }
-      CSFLogDebug(logTag, "%s: Encoder framerate changed to %u",
-       __FUNCTION__, mSendingFramerate);
-    }
-  }
-  return true;
+  return new_framerate;
 }
 
 MediaConduitErrorCode
 WebrtcVideoConduit::SetExternalSendCodec(VideoCodecConfig* config,
                                          VideoEncoder* encoder) {
   if (!mPtrExtCodec->RegisterExternalSendCodec(mChannel,
                                               config->mType,
                                               static_cast<WebrtcVideoEncoder*>(encoder),
@@ -1216,23 +1212,22 @@ WebrtcVideoConduit::SendVideoFrame(unsig
 
   // Transmission should be enabled before we insert any frames.
   if(!mEngineTransmitting)
   {
     CSFLogError(logTag, "%s Engine not transmitting ", __FUNCTION__);
     return kMediaConduitSessionNotInited;
   }
 
-  if (!SelectSendResolution(width, height, false))
   {
-    return kMediaConduitCaptureError;
-  }
-  if (!SelectSendFrameRate(mSendingFramerate))
-  {
-    return kMediaConduitCaptureError;
+    MutexAutoLock lock(mCodecMutex);
+    if (!SelectSendResolution(width, height))
+    {
+      return kMediaConduitCaptureError;
+    }
   }
   // insert the frame to video engine in I420 format only
   MOZ_ASSERT(mPtrExtCapture);
   if(mPtrExtCapture->IncomingFrame(video_frame,
                                    video_frame_length,
                                    width, height,
                                    type,
                                    (unsigned long long)capture_time) == -1)
@@ -1604,17 +1599,17 @@ WebrtcVideoConduit::CheckCodecForMatch(c
 }
 
 /**
  * Perform validation on the codecConfig to be applied
  * Verifies if the codec is already applied.
  */
 MediaConduitErrorCode
 WebrtcVideoConduit::ValidateCodecConfig(const VideoCodecConfig* codecInfo,
-                                        bool send) const
+                                        bool send)
 {
   bool codecAppliedAlready = false;
 
   if(!codecInfo)
   {
     CSFLogError(logTag, "%s Null CodecConfig ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
@@ -1624,16 +1619,18 @@ WebrtcVideoConduit::ValidateCodecConfig(
   {
     CSFLogError(logTag, "%s Invalid Payload Name Length ", __FUNCTION__);
     return kMediaConduitMalformedArgument;
   }
 
   //check if we have the same codec already applied
   if(send)
   {
+    MutexAutoLock lock(mCodecMutex);
+
     codecAppliedAlready = CheckCodecsForMatch(mCurSendCodecConfig,codecInfo);
   } else {
     codecAppliedAlready = CheckCodecForMatch(codecInfo);
   }
 
   if(codecAppliedAlready)
   {
     CSFLogDebug(logTag, "%s Codec %s Already Applied  ", __FUNCTION__, codecInfo->mName.c_str());
--- a/media/webrtc/signaling/src/media-conduit/VideoConduit.h
+++ b/media/webrtc/signaling/src/media-conduit/VideoConduit.h
@@ -140,25 +140,25 @@ public:
                        unsigned short height);
   /**
    * Function to select and change the encoding resolution based on incoming frame size
    * and current available bandwidth.
    * @param width, height: dimensions of the frame
    * @param force: force setting the codec config if framerate may require a bandwidth change
    */
   bool SelectSendResolution(unsigned short width,
-                            unsigned short height,
-                            bool force);
+                            unsigned short height);
 
   /**
    * Function to select and change the encoding frame rate based on incoming frame rate
    * and max-mbps setting.
-   * @param framerate
+   * @param current framerate
+   * @result new framerate
    */
-  bool SelectSendFrameRate(unsigned int framerate);
+  unsigned int SelectSendFrameRate(unsigned int framerate) const;
 
   /**
    * Function to deliver a capture video frame for encoding and transport
    * @param video_frame: pointer to captured video-frame.
    * @param video_frame_length: size of the frame
    * @param width, height: dimensions of the frame
    * @param video_type: Type of the video frame - I420, RAW
    * @param captured_time: timestamp when the frame was captured.
@@ -301,17 +301,17 @@ private:
 
   // Functions to verify if the codec passed is already in
   // conduits database
   bool CheckCodecForMatch(const VideoCodecConfig* codecInfo) const;
   bool CheckCodecsForMatch(const VideoCodecConfig* curCodecConfig,
                            const VideoCodecConfig* codecInfo) const;
 
   //Checks the codec to be applied
-  MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send) const;
+  MediaConduitErrorCode ValidateCodecConfig(const VideoCodecConfig* codecInfo, bool send);
 
   //Utility function to dump recv codec database
   void DumpCodecDB() const;
 
   // Video Latency Test averaging filter
   void VideoLatencyUpdate(uint64_t new_sample);
 
   webrtc::VideoEngine* mVideoEngine;
@@ -332,17 +332,20 @@ private:
 
   // Engine state we are concerned with.
   mozilla::Atomic<bool> mEngineTransmitting; //If true ==> Transmit Sub-system is up and running
   mozilla::Atomic<bool> mEngineReceiving;    // if true ==> Receive Sus-sysmtem up and running
 
   int mChannel; // Video Channel for this conduit
   int mCapId;   // Capturer for this conduit
   RecvCodecList    mRecvCodecList;
-  VideoCodecConfig* mCurSendCodecConfig;
+
+  Mutex mCodecMutex; // protects mCurrSendCodecConfig
+  nsAutoPtr<VideoCodecConfig> mCurSendCodecConfig;
+
   unsigned short mSendingWidth;
   unsigned short mSendingHeight;
   unsigned short mReceivingWidth;
   unsigned short mReceivingHeight;
   unsigned int   mSendingFramerate;
   // scaled by *10 because Atomic<double/float> isn't supported
   mozilla::Atomic<int32_t, mozilla::Relaxed> mLastFramerateTenths;
   unsigned short mNumReceivingStreams;
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -745,119 +745,95 @@ MediaPipeline::TransportInfo* MediaPipel
 
   return nullptr;
 }
 
 nsresult MediaPipeline::PipelineTransport::SendRtpPacket(
     const void *data, int len) {
 
     nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
-                                             len));
+                                             len, len + SRTP_MAX_EXPANSION));
 
     RUN_ON_THREAD(sts_thread_,
                   WrapRunnable(
                       RefPtr<MediaPipeline::PipelineTransport>(this),
-                      &MediaPipeline::PipelineTransport::SendRtpPacket_s,
-                      buf),
+                      &MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
+                      buf, true),
                   NS_DISPATCH_NORMAL);
 
     return NS_OK;
 }
 
-nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
-    nsAutoPtr<DataBuffer> data) {
+nsresult MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
+    nsAutoPtr<DataBuffer> data,
+    bool is_rtp) {
+
   ASSERT_ON_THREAD(sts_thread_);
-  if (!pipeline_)
+  if (!pipeline_) {
     return NS_OK;  // Detached
+  }
+  TransportInfo& transport = is_rtp ? pipeline_->rtp_ : pipeline_->rtcp_;
 
-  if (!pipeline_->rtp_.send_srtp_) {
-    MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP packet; SRTP not set up yet");
+  if (!transport.send_srtp_) {
+    MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP/RTCP packet; SRTP not set up yet");
     return NS_OK;
   }
 
-  MOZ_ASSERT(pipeline_->rtp_.transport_);
-  NS_ENSURE_TRUE(pipeline_->rtp_.transport_, NS_ERROR_NULL_POINTER);
+  MOZ_ASSERT(transport.transport_);
+  NS_ENSURE_TRUE(transport.transport_, NS_ERROR_NULL_POINTER);
 
-  // libsrtp enciphers in place, so we need a new, big enough
-  // buffer.
-  // XXX. allocates and deletes one buffer per packet sent.
-  // Bug 822129
-  int max_len = data->len() + SRTP_MAX_EXPANSION;
-  ScopedDeletePtr<unsigned char> inner_data(
-      new unsigned char[max_len]);
-  memcpy(inner_data, data->data(), data->len());
+  // libsrtp enciphers in place, so we need a big enough buffer.
+  MOZ_ASSERT(data->capacity() >= data->len() + SRTP_MAX_EXPANSION);
 
   int out_len;
-  nsresult res = pipeline_->rtp_.send_srtp_->ProtectRtp(inner_data,
-                                                        data->len(),
-                                                        max_len,
-                                                        &out_len);
-  if (!NS_SUCCEEDED(res))
+  nsresult res;
+  if (is_rtp) {
+    res = transport.send_srtp_->ProtectRtp(data->data(),
+                                           data->len(),
+                                           data->capacity(),
+                                           &out_len);
+  } else {
+    res = transport.send_srtp_->ProtectRtcp(data->data(),
+                                            data->len(),
+                                            data->capacity(),
+                                            &out_len);
+  }
+  if (!NS_SUCCEEDED(res)) {
     return res;
+  }
 
-  MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTP packet.");
-  pipeline_->increment_rtp_packets_sent(out_len);
-  return pipeline_->SendPacket(pipeline_->rtp_.transport_, inner_data,
-                               out_len);
+  // paranoia; don't have uninitialized bytes included in data->len()
+  data->SetLength(out_len);
+
+  MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending " <<
+            (is_rtp ? "RTP" : "RTCP") << " packet");
+  if (is_rtp) {
+    pipeline_->increment_rtp_packets_sent(out_len);
+  } else {
+    pipeline_->increment_rtcp_packets_sent();
+  }
+  return pipeline_->SendPacket(transport.transport_, data->data(), out_len);
 }
 
 nsresult MediaPipeline::PipelineTransport::SendRtcpPacket(
     const void *data, int len) {
 
     nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
-                                             len));
+                                             len, len + SRTP_MAX_EXPANSION));
 
     RUN_ON_THREAD(sts_thread_,
                   WrapRunnable(
                       RefPtr<MediaPipeline::PipelineTransport>(this),
-                      &MediaPipeline::PipelineTransport::SendRtcpPacket_s,
-                      buf),
+                      &MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
+                      buf, false),
                   NS_DISPATCH_NORMAL);
 
     return NS_OK;
 }
 
-nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
-    nsAutoPtr<DataBuffer> data) {
-  ASSERT_ON_THREAD(sts_thread_);
-  if (!pipeline_)
-    return NS_OK;  // Detached
-
-  if (!pipeline_->rtcp_.send_srtp_) {
-    MOZ_MTLOG(ML_DEBUG, "Couldn't write RTCP packet; SRTCP not set up yet");
-    return NS_OK;
-  }
-
-  MOZ_ASSERT(pipeline_->rtcp_.transport_);
-  NS_ENSURE_TRUE(pipeline_->rtcp_.transport_, NS_ERROR_NULL_POINTER);
-
-  // libsrtp enciphers in place, so we need a new, big enough
-  // buffer.
-  // XXX. allocates and deletes one buffer per packet sent.
-  // Bug 822129.
-  int max_len = data->len() + SRTP_MAX_EXPANSION;
-  ScopedDeletePtr<unsigned char> inner_data(
-      new unsigned char[max_len]);
-  memcpy(inner_data, data->data(), data->len());
-
-  int out_len;
-  nsresult res = pipeline_->rtcp_.send_srtp_->ProtectRtcp(inner_data,
-                                                          data->len(),
-                                                          max_len,
-                                                          &out_len);
-
-  if (!NS_SUCCEEDED(res))
-    return res;
-
-  MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTCP packet.");
-  pipeline_->increment_rtcp_packets_sent();
-  return pipeline_->SendPacket(pipeline_->rtcp_.transport_, inner_data,
-                               out_len);
-}
-
 void MediaPipelineTransmit::PipelineListener::
 UnsetTrackId(MediaStreamGraphImpl* graph) {
 #ifndef USE_FAKE_MEDIA_STREAMS
   class Message : public ControlMessage {
   public:
     explicit Message(PipelineListener* listener) :
       ControlMessage(nullptr), listener_(listener) {}
     virtual void Run() override
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.h
@@ -186,18 +186,18 @@ class MediaPipeline : public sigslot::ha
 
     void Detach() { pipeline_ = nullptr; }
     MediaPipeline *pipeline() const { return pipeline_; }
 
     virtual nsresult SendRtpPacket(const void* data, int len);
     virtual nsresult SendRtcpPacket(const void* data, int len);
 
    private:
-    virtual nsresult SendRtpPacket_s(nsAutoPtr<DataBuffer> data);
-    virtual nsresult SendRtcpPacket_s(nsAutoPtr<DataBuffer> data);
+    nsresult SendRtpRtcpPacket_s(nsAutoPtr<DataBuffer> data,
+                                 bool is_rtp);
 
     MediaPipeline *pipeline_;  // Raw pointer to avoid cycles
     nsCOMPtr<nsIEventTarget> sts_thread_;
   };
   friend class PipelineTransport;
 
   class TransportInfo {
     public:
--- a/media/webrtc/signaling/src/mediapipeline/SrtpFlow.h
+++ b/media/webrtc/signaling/src/mediapipeline/SrtpFlow.h
@@ -17,19 +17,19 @@ typedef struct srtp_ctx_t *srtp_t;
 typedef struct srtp_event_data_t srtp_event_data_t;
 
 namespace mozilla {
 
 #define SRTP_MASTER_KEY_LENGTH 16
 #define SRTP_MASTER_SALT_LENGTH 14
 #define SRTP_TOTAL_KEY_LENGTH (SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_SALT_LENGTH)
 
-// For some reason libsrtp increases packet size by > 12 for RTCP even though
-// the doc claims otherwise.
-#define SRTP_MAX_EXPANSION 20
+// SRTCP requires an auth tag *plus* a 4-byte index-plus-'E'-bit value (see
+// RFC 3711)
+#define SRTP_MAX_EXPANSION (SRTP_MAX_TRAILER_LEN+4)
 
 
 class SrtpFlow {
   ~SrtpFlow();
  public:
 
 
   static mozilla::RefPtr<SrtpFlow> Create(int cipher_suite,
--- a/memory/replace/dmd/DMD.cpp
+++ b/memory/replace/dmd/DMD.cpp
@@ -365,16 +365,18 @@ class Options
 
 public:
   explicit Options(const char* aDMDEnvVar);
 
   bool IsLiveMode()       const { return mMode == Live; }
   bool IsDarkMatterMode() const { return mMode == DarkMatter; }
   bool IsCumulativeMode() const { return mMode == Cumulative; }
 
+  const char* ModeString() const;
+
   const char* DMDEnvVar() const { return mDMDEnvVar; }
 
   size_t SampleBelowSize() const { return mSampleBelowSize.mActual; }
   size_t MaxFrames()       const { return mMaxFrames.mActual; }
   size_t ShowDumpStats()   const { return mShowDumpStats; }
 };
 
 static Options *gOptions;
@@ -1493,16 +1495,32 @@ Options::BadArg(const char* aArg)
   StatusMsg("  --max-frames=<1..%d>         Max. depth of stack traces [%d]\n",
             int(mMaxFrames.mMax),
             int(mMaxFrames.mDefault));
   StatusMsg("  --show-dump-stats=<yes|no>   Show stats about dumps? [no]\n");
   StatusMsg("\n");
   exit(1);
 }
 
+const char*
+Options::ModeString() const
+{
+  switch (mMode) {
+  case Live:
+    return "live";
+  case DarkMatter:
+    return "dark-matter";
+  case Cumulative:
+    return "cumulative";
+  default:
+    MOZ_ASSERT(false);
+    return "(unknown DMD mode)";
+  }
+}
+
 //---------------------------------------------------------------------------
 // DMD start-up
 //---------------------------------------------------------------------------
 
 #ifdef XP_MACOSX
 static void
 NopStackWalkCallback(uint32_t aFrameNumber, void* aPc, void* aSp,
                      void* aClosure)
@@ -1775,29 +1793,17 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWr
     {
       const char* var = gOptions->DMDEnvVar();
       if (var) {
         writer.StringProperty("dmdEnvVar", var);
       } else {
         writer.NullProperty("dmdEnvVar");
       }
 
-      const char* mode;
-      if (gOptions->IsLiveMode()) {
-        mode = "live";
-      } else if (gOptions->IsDarkMatterMode()) {
-        mode = "dark-matter";
-      } else if (gOptions->IsCumulativeMode()) {
-        mode = "cumulative";
-      } else {
-        MOZ_ASSERT(false);
-        mode = "(unknown DMD mode)";
-      }
-      writer.StringProperty("mode", mode);
-
+      writer.StringProperty("mode", gOptions->ModeString());
       writer.IntProperty("sampleBelowSize", gOptions->SampleBelowSize());
     }
     writer.EndObject();
 
     StatusMsg("  Constructing the heap block list...\n");
 
     ToIdStringConverter isc;
 
@@ -1813,17 +1819,16 @@ AnalyzeImpl(UniquePtr<JSONWriteFunc> aWr
           if (!b.IsSampled()) {
             writer.IntProperty("req", b.ReqSize());
             if (b.SlopSize() > 0) {
               writer.IntProperty("slop", b.SlopSize());
             }
           }
           writer.StringProperty("alloc", isc.ToIdString(b.AllocStackTrace()));
           if (gOptions->IsDarkMatterMode() && b.NumReports() > 0) {
-            MOZ_ASSERT(gOptions->IsDarkMatterMode());
             writer.StartArrayProperty("reps");
             {
               if (b.ReportStackTrace1()) {
                 writer.StringElement(isc.ToIdString(b.ReportStackTrace1()));
               }
               if (b.ReportStackTrace2()) {
                 writer.StringElement(isc.ToIdString(b.ReportStackTrace2()));
               }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -911,8 +911,13 @@ pref("touchcaret.extendedvisibility", tr
 pref("caret.manages-android-actionbar", true);
 
 // Disable sending console to logcat on release builds.
 #ifdef RELEASE_BUILD
 pref("consoleservice.logcat", false);
 #else
 pref("consoleservice.logcat", true);
 #endif
+
+// Enable Service Workers for Android on non-release builds
+#ifndef RELEASE_BUILD
+pref("dom.serviceWorkers.enabled", true);
+#endif
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -690,16 +690,26 @@ nsJARChannel::OverrideSecurityInfo(nsISu
   MOZ_RELEASE_ASSERT(aSecurityInfo,
                      "This can only be called with a valid security info object");
   MOZ_RELEASE_ASSERT(ShouldIntercept(),
                      "This can only be called on channels that can be intercepted");
   mSecurityInfo = aSecurityInfo;
   return NS_OK;
 }
 
+void
+nsJARChannel::OverrideURI(nsIURI* aRedirectedURI)
+{
+  MOZ_RELEASE_ASSERT(mLoadFlags & LOAD_REPLACE,
+                     "This can only happen if the LOAD_REPLACE flag is set");
+  MOZ_RELEASE_ASSERT(ShouldIntercept(),
+                     "This can only be called on channels that can be intercepted");
+  mAppURI = aRedirectedURI;
+}
+
 NS_IMETHODIMP
 nsJARChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
 {
     NS_PRECONDITION(aSecurityInfo, "Null out param");
     NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
     return NS_OK;
 }
 
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -57,16 +57,17 @@ public:
     NS_DECL_NSITHREADRETARGETABLEREQUEST
     NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
     nsJARChannel();
 
     nsresult Init(nsIURI *uri);
 
     nsresult OverrideSecurityInfo(nsISupports* aSecurityInfo);
+    void OverrideURI(nsIURI* aRedirectedURI);
 
 private:
     virtual ~nsJARChannel();
 
     nsresult CreateJarInput(nsIZipReaderCache *, nsJARInputThunk **);
     nsresult LookupFile(bool aAllowAsync);
     nsresult OpenLocalFile();
     void NotifyError(nsresult aError);
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -1431,16 +1431,26 @@ HttpBaseChannel::OverrideSecurityInfo(ns
   MOZ_RELEASE_ASSERT(aSecurityInfo,
                      "This can only be called with a valid security info object");
   MOZ_RELEASE_ASSERT(ShouldIntercept(),
                      "This can only be called on channels that can be intercepted");
   mSecurityInfo = aSecurityInfo;
   return NS_OK;
 }
 
+void
+HttpBaseChannel::OverrideURI(nsIURI* aRedirectedURI)
+{
+  MOZ_RELEASE_ASSERT(mLoadFlags & LOAD_REPLACE,
+                     "This can only happen if the LOAD_REPLACE flag is set");
+  MOZ_RELEASE_ASSERT(ShouldIntercept(),
+                     "This can only be called on channels that can be intercepted");
+  mURI = aRedirectedURI;
+}
+
 NS_IMETHODIMP
 HttpBaseChannel::IsNoStoreResponse(bool *value)
 {
   if (!mResponseHead)
     return NS_ERROR_NOT_AVAILABLE;
   *value = mResponseHead->NoStore();
   return NS_OK;
 }
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -244,16 +244,17 @@ public:
 
     nsHttpResponseHead * GetResponseHead() const { return mResponseHead; }
     nsHttpRequestHead * GetRequestHead() { return &mRequestHead; }
 
     const NetAddr& GetSelfAddr() { return mSelfAddr; }
     const NetAddr& GetPeerAddr() { return mPeerAddr; }
 
     nsresult OverrideSecurityInfo(nsISupports* aSecurityInfo);
+    void OverrideURI(nsIURI* aRedirectedURI);
 
 public: /* Necko internal use only... */
     bool IsNavigation();
 
     // Return whether upon a redirect code of httpStatus for method, the
     // request method should be rewritten to GET.
     static bool ShouldRewriteRedirectToGET(uint32_t httpStatus,
                                            nsHttpRequestHead::ParsedMethodType method);
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2726,17 +2726,25 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
     nsCOMPtr<nsICacheStorage> cacheStorage;
     nsCOMPtr<nsIURI> openURI;
     if (!mFallbackKey.IsEmpty() && mFallbackChannel) {
         // This is a fallback channel, open fallback URI instead
         rv = NS_NewURI(getter_AddRefs(openURI), mFallbackKey);
         NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
-        openURI = mURI;
+        // In the case of intercepted channels, we need to construct the cache
+        // entry key based on the original URI, so that in case the intercepted
+        // channel is redirected, the cache entry key before and after the
+        // redirect is the same.
+        if (PossiblyIntercepted()) {
+            openURI = mOriginalURI;
+        } else {
+            openURI = mURI;
+        }
     }
 
     uint32_t appId = info->AppId();
     bool appOffline = false;
 
     if (appId != NECKO_NO_APP_ID) {
         gIOService->IsAppOffline(appId, &appOffline);
         LOG(("nsHttpChannel::OpenCacheEntry appId: %u, offline: %d\n", appId, appOffline));
@@ -2804,16 +2812,21 @@ nsHttpChannel::OpenCacheEntry(bool isHtt
 
         nsCOMPtr<nsINetworkInterceptController> controller;
         GetCallback(controller);
 
         nsRefPtr<InterceptedChannelChrome> intercepted =
                 new InterceptedChannelChrome(this, controller, entry);
         intercepted->NotifyController();
     } else {
+        if (mInterceptCache == INTERCEPTED) {
+            DebugOnly<bool> exists;
+            MOZ_ASSERT(NS_SUCCEEDED(cacheStorage->Exists(openURI, extension, &exists)) && exists,
+                       "The entry must exist in the cache after we create it here");
+        }
         rv = cacheStorage->AsyncOpenURI(openURI, extension, cacheEntryOpenFlags, this);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     waitFlags.Keep(WAIT_FOR_CACHE_ENTRY);
 
 bypassCacheEntryOpen:
     if (!mApplicationCacheForWrite)
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -28,17 +28,21 @@
 #include <sys/syscall.h>
 #include <sys/time.h>
 #include <unistd.h>
 
 #include "mozilla/Atomics.h"
 #include "mozilla/SandboxInfo.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
 #if defined(ANDROID)
 #include "sandbox/linux/services/android_ucontext.h"
 #endif
 #include "sandbox/linux/services/linux_syscalls.h"
 
 #ifdef MOZ_ASAN
 // Copy libsanitizer declarations to avoid depending on ASAN headers.
 // See also bug 1081242 comment #4.
@@ -64,136 +68,130 @@ namespace mozilla {
 #ifdef ANDROID
 SandboxCrashFunc gSandboxCrashFunc;
 #endif
 
 #ifdef MOZ_GMP_SANDBOX
 // For media plugins, we can start the sandbox before we dlopen the
 // module, so we have to pre-open the file and simulate the sandboxed
 // open().
-static int gMediaPluginFileDesc = -1;
-static const char *gMediaPluginFilePath;
+static SandboxOpenedFile gMediaPluginFile;
 #endif
 
 static UniquePtr<SandboxChroot> gChrootHelper;
+static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
+
+// Test whether a ucontext, interpreted as the state after a syscall,
+// indicates the given error.  See also sandbox::Syscall::PutValueInUcontext.
+static bool
+ContextIsError(const ucontext_t *aContext, int aError)
+{
+  // Avoid integer promotion warnings.  (The unary addition makes
+  // the decltype not evaluate to a reference type.)
+  typedef decltype(+SECCOMP_RESULT(aContext)) reg_t;
+
+#ifdef __mips__
+  return SECCOMP_PARM4(aContext) != 0
+    && SECCOMP_RESULT(aContext) == static_cast<reg_t>(aError);
+#else
+  return SECCOMP_RESULT(aContext) == static_cast<reg_t>(-aError);
+#endif
+}
 
 /**
- * This is the SIGSYS handler function. It is used to report to the user
- * which system call has been denied by Seccomp.
- * This function also makes the process exit as denying the system call
- * will otherwise generally lead to unexpected behavior from the process,
- * since we don't know if all functions will handle such denials gracefully.
+ * This is the SIGSYS handler function.  It delegates to the Chromium
+ * TrapRegistry handler (see InstallSigSysHandler, below) and, if the
+ * trap handler installed by the policy would fail with ENOSYS,
+ * crashes the process.  This allows unintentional policy failures to
+ * be reported as crash dumps and fixed.  It also logs information
+ * about the failed system call.
  *
- * @see InstallSyscallReporter() function.
+ * Note that this could be invoked in parallel on multiple threads and
+ * that it could be in async signal context (e.g., intercepting an
+ * open() called from an async signal handler).
  */
 static void
-Reporter(int nr, siginfo_t *info, void *void_context)
+SigSysHandler(int nr, siginfo_t *info, void *void_context)
 {
   ucontext_t *ctx = static_cast<ucontext_t*>(void_context);
-  unsigned long syscall_nr, args[6];
-  pid_t pid = getpid();
-
-  if (nr != SIGSYS) {
-    return;
-  }
-  if (info->si_code != SYS_SECCOMP) {
-    return;
-  }
+  // This shouldn't ever be null, but the Chromium handler checks for
+  // that and refrains from crashing, so let's not crash release builds:
+  MOZ_DIAGNOSTIC_ASSERT(ctx);
   if (!ctx) {
     return;
   }
 
-  syscall_nr = SECCOMP_SYSCALL(ctx);
-  args[0] = SECCOMP_PARM1(ctx);
-  args[1] = SECCOMP_PARM2(ctx);
-  args[2] = SECCOMP_PARM3(ctx);
-  args[3] = SECCOMP_PARM4(ctx);
-  args[4] = SECCOMP_PARM5(ctx);
-  args[5] = SECCOMP_PARM6(ctx);
+  // Save a copy of the context before invoking the trap handler,
+  // which will overwrite one or more registers with the return value.
+  ucontext_t savedCtx = *ctx;
 
-#if defined(ANDROID) && ANDROID_VERSION < 16
-  // Bug 1093893: Translate tkill to tgkill for pthread_kill; fixed in
-  // bionic commit 10c8ce59a (in JB and up; API level 16 = Android 4.1).
-  if (syscall_nr == __NR_tkill) {
-    intptr_t ret = syscall(__NR_tgkill, getpid(), args[0], args[1]);
-    if (ret < 0) {
-      ret = -errno;
-    }
-    SECCOMP_RESULT(ctx) = ret;
+  gChromiumSigSysHandler(nr, info, ctx);
+  if (!ContextIsError(ctx, ENOSYS)) {
     return;
   }
-#endif
-
-#ifdef MOZ_GMP_SANDBOX
-  if (syscall_nr == __NR_open && gMediaPluginFilePath) {
-    const char *path = reinterpret_cast<const char*>(args[0]);
-    int flags = int(args[1]);
 
-    if ((flags & O_ACCMODE) != O_RDONLY) {
-      SANDBOX_LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
-                        path, flags);
-    } else if (strcmp(path, gMediaPluginFilePath) != 0) {
-      SANDBOX_LOG_ERROR("attempt to open file %s which is not the media plugin"
-                        " %s", path, gMediaPluginFilePath);
-    } else if (gMediaPluginFileDesc == -1) {
-      SANDBOX_LOG_ERROR("multiple opens of media plugin file unimplemented");
-    } else {
-      SECCOMP_RESULT(ctx) = gMediaPluginFileDesc;
-      gMediaPluginFileDesc = -1;
-      return;
-    }
-  }
-#endif
+  pid_t pid = getpid();
+  unsigned long syscall_nr = SECCOMP_SYSCALL(&savedCtx);
+  unsigned long args[6];
+  args[0] = SECCOMP_PARM1(&savedCtx);
+  args[1] = SECCOMP_PARM2(&savedCtx);
+  args[2] = SECCOMP_PARM3(&savedCtx);
+  args[3] = SECCOMP_PARM4(&savedCtx);
+  args[4] = SECCOMP_PARM5(&savedCtx);
+  args[5] = SECCOMP_PARM6(&savedCtx);
 
+  // TODO, someday when this is enabled on MIPS: include the two extra
+  // args in the error message.
   SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, syscall %lu,"
                     " args %lu %lu %lu %lu %lu %lu.  Killing process.",
                     pid, syscall_nr,
                     args[0], args[1], args[2], args[3], args[4], args[5]);
 
   // Bug 1017393: record syscall number somewhere useful.
   info->si_addr = reinterpret_cast<void*>(syscall_nr);
 
-  gSandboxCrashFunc(nr, info, void_context);
+  gSandboxCrashFunc(nr, info, &savedCtx);
   _exit(127);
 }
 
 /**
- * The reporter is called when the process receives a SIGSYS signal.
- * The signal is sent by the kernel when Seccomp encounter a system call
- * that has not been allowed.
- * We register an action for that signal (calling the Reporter function).
- *
- * This function should not be used in production and thus generally be
- * called from debug code. In production, the process is directly killed.
- * For this reason, the function is ifdef'd, as there is no reason to
- * compile it while unused.
- *
- * @return 0 on success, -1 on failure.
- * @see Reporter() function.
+ * This function installs the SIGSYS handler.  This is slightly
+ * complicated because we want to use Chromium's handler to dispatch
+ * to specific trap handlers defined in the policy, but we also need
+ * the full original signal context to give to Breakpad for crash
+ * dumps.  So we install Chromium's handler first, then retrieve its
+ * address so our replacement can delegate to it.
  */
-static int
-InstallSyscallReporter(void)
+static void
+InstallSigSysHandler(void)
 {
   struct sigaction act;
-  sigset_t mask;
-  memset(&act, 0, sizeof(act));
-  sigemptyset(&mask);
-  sigaddset(&mask, SIGSYS);
+
+  // Ensure that the Chromium handler is installed.
+  unused << sandbox::Trap::Registry();
+
+  // If the signal handling state isn't as expected, crash now instead
+  // of crashing later (and more confusingly) when SIGSYS happens.
 
-  act.sa_sigaction = &Reporter;
-  act.sa_flags = SA_SIGINFO | SA_NODEFER;
+  if (sigaction(SIGSYS, nullptr, &act) != 0) {
+    MOZ_CRASH("Couldn't read old SIGSYS disposition");
+  }
+  if ((act.sa_flags & SA_SIGINFO) != SA_SIGINFO) {
+    MOZ_CRASH("SIGSYS not already set to a siginfo handler?");
+  }
+  MOZ_RELEASE_ASSERT(act.sa_sigaction);
+  gChromiumSigSysHandler = act.sa_sigaction;
+  act.sa_sigaction = SigSysHandler;
+  // Currently, SA_NODEFER should already be set by the Chromium code,
+  // but it's harmless to ensure that it's set:
+  MOZ_ASSERT(act.sa_flags & SA_NODEFER);
+  act.sa_flags |= SA_NODEFER;
   if (sigaction(SIGSYS, &act, nullptr) < 0) {
-    return -1;
+    MOZ_CRASH("Couldn't change SIGSYS disposition");
   }
-  if (sigemptyset(&mask) ||
-    sigaddset(&mask, SIGSYS) ||
-    sigprocmask(SIG_UNBLOCK, &mask, nullptr)) {
-      return -1;
-  }
-  return 0;
 }
 
 /**
  * This function installs the syscall filter, a.k.a. seccomp.
  * PR_SET_NO_NEW_PRIVS ensures that it is impossible to grant more
  * syscalls to the process beyond this point (even after fork()).
  * SECCOMP_MODE_FILTER is the "bpf" mode of seccomp which allows
  * to pass a bpf program (in our case, it contains a syscall
@@ -215,19 +213,19 @@ InstallSyscallFilter(const sock_fprog *p
     SANDBOX_LOG_ERROR("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER) failed: %s",
                       strerror(errno));
     MOZ_CRASH("prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER)");
   }
 }
 
 // Use signals for permissions that need to be set per-thread.
 // The communication channel from the signal handler back to the main thread.
-static mozilla::Atomic<int> sSetSandboxDone;
+static mozilla::Atomic<int> gSetSandboxDone;
 // Pass the filter itself through a global.
-static const sock_fprog *sSetSandboxFilter;
+static sock_fprog gSetSandboxFilter;
 
 // We have to dynamically allocate the signal number; see bug 1038900.
 // This function returns the first realtime signal currently set to
 // default handling (i.e., not in use), or 0 if none could be found.
 //
 // WARNING: if this function or anything similar to it (including in
 // external libraries) is used on multiple threads concurrently, there
 // will be a race condition.
@@ -247,47 +245,52 @@ FindFreeSignalNumber()
 }
 
 // Returns true if sandboxing was enabled, or false if sandboxing
 // already was enabled.  Crashes if sandboxing could not be enabled.
 static bool
 SetThreadSandbox()
 {
   if (prctl(PR_GET_SECCOMP, 0, 0, 0, 0) == 0) {
-    InstallSyscallFilter(sSetSandboxFilter);
+    InstallSyscallFilter(&gSetSandboxFilter);
     return true;
   }
   return false;
 }
 
 static void
 SetThreadSandboxHandler(int signum)
 {
   // The non-zero number sent back to the main thread indicates
   // whether action was taken.
   if (SetThreadSandbox()) {
-    sSetSandboxDone = 2;
+    gSetSandboxDone = 2;
   } else {
-    sSetSandboxDone = 1;
+    gSetSandboxDone = 1;
   }
   // Wake up the main thread.  See the FUTEX_WAIT call, below, for an
   // explanation.
-  syscall(__NR_futex, reinterpret_cast<int*>(&sSetSandboxDone),
+  syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone),
           FUTEX_WAKE, 1);
 }
 
 static void
-BroadcastSetThreadSandbox(SandboxType aType)
+BroadcastSetThreadSandbox(UniquePtr<sock_filter[]> aProgram, size_t aProgLen)
 {
   int signum;
   pid_t pid, tid, myTid;
   DIR *taskdp;
   struct dirent *de;
-  SandboxFilter filter(&sSetSandboxFilter, aType,
-                       SandboxInfo::Get().Test(SandboxInfo::kVerbose));
+
+  // Note: this is an unsafe copy of the unique pointer, but it's
+  // zeroed (and the signal handler that would access it is removed)
+  // before the end of this function.
+  gSetSandboxFilter.filter = aProgram.get();
+  gSetSandboxFilter.len = static_cast<unsigned short>(aProgLen);
+  MOZ_RELEASE_ASSERT(static_cast<size_t>(gSetSandboxFilter.len) == aProgLen);
 
   static_assert(sizeof(mozilla::Atomic<int>) == sizeof(int),
                 "mozilla::Atomic<int> isn't represented by an int");
   pid = getpid();
   myTid = syscall(__NR_gettid);
   taskdp = opendir("/proc/self/task");
   if (taskdp == nullptr) {
     SANDBOX_LOG_ERROR("opendir /proc/self/task: %s\n", strerror(errno));
@@ -327,17 +330,17 @@ BroadcastSetThreadSandbox(SandboxType aT
         continue;
       }
       if (tid == myTid) {
         // Drop this thread's privileges last, below, so we can
         // continue to signal other threads.
         continue;
       }
       // Reset the futex cell and signal.
-      sSetSandboxDone = 0;
+      gSetSandboxDone = 0;
       if (syscall(__NR_tgkill, pid, tid, signum) != 0) {
         if (errno == ESRCH) {
           SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
           // Rescan threads, in case it forked before exiting.
           sandboxProgress = true;
           continue;
         }
         SANDBOX_LOG_ERROR("tgkill(%d,%d): %s\n", pid, tid, strerror(errno));
@@ -358,27 +361,27 @@ BroadcastSetThreadSandbox(SandboxType aT
       // blocking forever or silently losing security, and it
       // shouldn't actually happen.
       static const int crashDelay = 10; // seconds
       struct timespec timeLimit;
       clock_gettime(CLOCK_MONOTONIC, &timeLimit);
       timeLimit.tv_sec += crashDelay;
       while (true) {
         static const struct timespec futexTimeout = { 0, 10*1000*1000 }; // 10ms
-        // Atomically: if sSetSandboxDone == 0, then sleep.
-        if (syscall(__NR_futex, reinterpret_cast<int*>(&sSetSandboxDone),
+        // Atomically: if gSetSandboxDone == 0, then sleep.
+        if (syscall(__NR_futex, reinterpret_cast<int*>(&gSetSandboxDone),
                   FUTEX_WAIT, 0, &futexTimeout) != 0) {
           if (errno != EWOULDBLOCK && errno != ETIMEDOUT && errno != EINTR) {
             SANDBOX_LOG_ERROR("FUTEX_WAIT: %s\n", strerror(errno));
             MOZ_CRASH();
           }
         }
         // Did the handler finish?
-        if (sSetSandboxDone > 0) {
-          if (sSetSandboxDone == 2) {
+        if (gSetSandboxDone > 0) {
+          if (gSetSandboxDone == 2) {
             sandboxProgress = true;
           }
           break;
         }
         // Has the thread ceased to exist?
         if (syscall(__NR_tgkill, pid, tid, 0) != 0) {
           if (errno == ESRCH) {
             SANDBOX_LOG_ERROR("Thread %d unexpectedly exited.", tid);
@@ -408,37 +411,51 @@ BroadcastSetThreadSandbox(SandboxType aT
     // See the comment on FindFreeSignalNumber about race conditions.
     SANDBOX_LOG_ERROR("handler for signal %d was changed to %p!",
                       signum, oldHandler);
     MOZ_CRASH();
   }
   unused << closedir(taskdp);
   // And now, deprivilege the main thread:
   SetThreadSandbox();
+  gSetSandboxFilter.filter = nullptr;
 }
 
 // Common code for sandbox startup.
 static void
-SetCurrentProcessSandbox(SandboxType aType)
+SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)
 {
   MOZ_ASSERT(gSandboxCrashFunc);
 
-  if (InstallSyscallReporter()) {
-    SANDBOX_LOG_ERROR("install_syscall_reporter() failed\n");
+  // Note: PolicyCompiler borrows the policy and registry for its
+  // lifetime, but does not take ownership of them.
+  sandbox::bpf_dsl::PolicyCompiler compiler(aPolicy.get(),
+                                            sandbox::Trap::Registry());
+  auto program = compiler.Compile();
+  if (SandboxInfo::Get().Test(SandboxInfo::kVerbose)) {
+    sandbox::bpf_dsl::DumpBPF::PrintProgram(*program);
   }
 
+  InstallSigSysHandler();
+
 #ifdef MOZ_ASAN
   __sanitizer_sandbox_arguments asanArgs;
   asanArgs.coverage_sandboxed = 1;
   asanArgs.coverage_fd = -1;
   asanArgs.coverage_max_block_size = 0;
   __sanitizer_sandbox_on_notify(&asanArgs);
 #endif
 
-  BroadcastSetThreadSandbox(aType);
+  // The syscall takes a C-style array, so copy the vector into one.
+  UniquePtr<sock_filter[]> flatProgram(new sock_filter[program->size()]);
+  for (auto i = program->begin(); i != program->end(); ++i) {
+    flatProgram[i - program->begin()] = *i;
+  }
+
+  BroadcastSetThreadSandbox(Move(flatProgram), program->size());
 }
 
 void
 SandboxEarlyInit(GeckoProcessType aType, bool aIsNuwa)
 {
   MOZ_RELEASE_ASSERT(IsSingleThreaded());
 
   // Which kinds of resource isolation (of those that need to be set
@@ -525,46 +542,49 @@ SandboxEarlyInit(GeckoProcessType aType,
 */
 void
 SetContentProcessSandbox()
 {
   if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForContent)) {
     return;
   }
 
-  SetCurrentProcessSandbox(kSandboxContentProcess);
+  SetCurrentProcessSandbox(GetContentSandboxPolicy());
 }
 #endif // MOZ_CONTENT_SANDBOX
 
 #ifdef MOZ_GMP_SANDBOX
 /**
  * Starts the seccomp sandbox for a media plugin process.  Should be
  * called only once, and before any potentially harmful content is
  * loaded -- including the plugin itself, if it's considered untrusted.
  *
- * The file indicated by aFilePath, if non-null, can be open()ed once
- * read-only after the sandbox starts; it should be the .so file
- * implementing the not-yet-loaded plugin.
+ * The file indicated by aFilePath, if non-null, can be open()ed
+ * read-only, once, after the sandbox starts; it should be the .so
+ * file implementing the not-yet-loaded plugin.
  *
  * Will normally make the process exit on failure.
 */
 void
 SetMediaPluginSandbox(const char *aFilePath)
 {
   if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia)) {
     return;
   }
 
+  MOZ_ASSERT(!gMediaPluginFile.mPath);
   if (aFilePath) {
-    gMediaPluginFilePath = strdup(aFilePath);
-    gMediaPluginFileDesc = open(aFilePath, O_RDONLY | O_CLOEXEC);
-    if (gMediaPluginFileDesc == -1) {
+    gMediaPluginFile.mPath = strdup(aFilePath);
+    gMediaPluginFile.mFd = open(aFilePath, O_RDONLY | O_CLOEXEC);
+    if (gMediaPluginFile.mFd == -1) {
       SANDBOX_LOG_ERROR("failed to open plugin file %s: %s",
                         aFilePath, strerror(errno));
       MOZ_CRASH();
     }
+  } else {
+    gMediaPluginFile.mFd = -1;
   }
   // Finally, start the sandbox.
-  SetCurrentProcessSandbox(kSandboxMediaPlugin);
+  SetCurrentProcessSandbox(GetMediaSandboxPolicy(&gMediaPluginFile));
 }
 #endif // MOZ_GMP_SANDBOX
 
 } // namespace mozilla
deleted file mode 100644
--- a/security/sandbox/linux/SandboxAssembler.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "SandboxAssembler.h"
-
-#include <errno.h>
-#include <utility>
-
-#include "sandbox/linux/bpf_dsl/dump_bpf.h"
-#include "sandbox/linux/bpf_dsl/trap_registry.h"
-#include "sandbox/linux/seccomp-bpf/codegen.h"
-#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
-
-namespace mozilla {
-
-// Need this for the SECCOMP_*_IDX macros to work.
-using sandbox::arch_seccomp_data;
-
-class SandboxAssemblerImpl {
-  typedef sandbox::Instruction* NodePtr;
-
-  sandbox::CodeGen mCode;
-  NodePtr mHead;
-
-  NodePtr RetAllow();
-  NodePtr RetDeny(int aErrno);
-  NodePtr RetKill();
-  NodePtr LoadArch(NodePtr aNext);
-  NodePtr LoadSyscall(NodePtr aNext);
-  NodePtr LoadArgHi(int aArg, NodePtr aNext);
-  NodePtr LoadArgLo(int aArg, NodePtr aNext);
-  NodePtr JmpEq(uint32_t aValue, NodePtr aThen, NodePtr aElse);
-public:
-  SandboxAssemblerImpl();
-  void PrependCheck(int aMaybeError, int aSyscallNr);
-  void PrependCheck(int aMaybeError, int aSyscallNr, int aArgChecked,
-                    const std::vector<uint32_t>& aArgValues);
-  void Compile(std::vector<sock_filter>* aProgram, bool aPrint);
-};
-
-void
-SandboxAssemblerImpl::Compile(std::vector<sock_filter>* aProgram, bool aPrint)
-{
-  NodePtr prog = LoadSyscall(mHead);
-  prog = LoadArch(JmpEq(SECCOMP_ARCH, prog, RetKill()));
-
-  mCode.Compile(prog, aProgram);
-  if (aPrint) {
-    sandbox::bpf_dsl::DumpBPF::PrintProgram(*aProgram);
-  }
-}
-
-void
-SandboxAssemblerImpl::PrependCheck(int aMaybeError, int aSyscallNr)
-{
-  NodePtr ret = aMaybeError ? RetDeny(aMaybeError) : RetAllow();
-  mHead = JmpEq(aSyscallNr, ret, mHead);
-}
-
-void
-SandboxAssemblerImpl::PrependCheck(int aMaybeError, int aSyscallNr,
-                                   int aArgChecked,
-                                   const std::vector<uint32_t>& aArgValues)
-{
-  NodePtr ret = aMaybeError ? RetDeny(aMaybeError) : RetAllow();
-  NodePtr noMatch = mHead;
-  NodePtr checkArg = LoadSyscall(noMatch);
-
-  // Loop backwards, prepending checks onto the no-match base case.
-  for (auto i = aArgValues.rbegin(); i != aArgValues.rend(); ++i) {
-    checkArg = JmpEq(*i, ret, checkArg);
-  }
-  checkArg = LoadArgLo(aArgChecked, checkArg);
-  checkArg = LoadArgHi(aArgChecked, JmpEq(0, checkArg, RetKill()));
-
-  mHead = JmpEq(aSyscallNr, checkArg, noMatch);
-}
-
-SandboxAssemblerImpl::SandboxAssemblerImpl() {
-  mHead = RetKill();
-}
-
-void
-SandboxAssembler::Compile(std::vector<sock_filter>* aProgram, bool aPrint)
-{
-  SandboxAssemblerImpl impl;
-
-  for (auto i = mRuleStack.rbegin(); i != mRuleStack.rend(); ++i) {
-    if (i->second.mCheckingArg) {
-      impl.PrependCheck(i->first, i->second.mSyscallNr, i->second.mArgChecked,
-                        i->second.mArgValues);
-    } else {
-      impl.PrependCheck(i->first, i->second.mSyscallNr);
-    }
-  }
-
-  impl.Compile(aProgram, aPrint);
-}
-
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::LoadArch(NodePtr aNext)
-{
-  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
-                               SECCOMP_ARCH_IDX,
-                               aNext);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::LoadSyscall(NodePtr aNext)
-{
-  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
-                               SECCOMP_NR_IDX,
-                               aNext);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::LoadArgHi(int aArg, NodePtr aNext)
-{
-  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
-                               SECCOMP_ARG_MSB_IDX(aArg),
-                               aNext);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::LoadArgLo(int aArg, NodePtr aNext)
-{
-  return mCode.MakeInstruction(BPF_LD + BPF_W + BPF_ABS,
-                               SECCOMP_ARG_LSB_IDX(aArg),
-                               aNext);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::JmpEq(uint32_t aValue, NodePtr aThen, NodePtr aElse)
-{
-  return mCode.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K,
-                               aValue, aThen, aElse);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::RetAllow()
-{
-  return mCode.MakeInstruction(BPF_RET + BPF_K,
-                               SECCOMP_RET_ALLOW,
-                               nullptr);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::RetDeny(int aErrno)
-{
-  return mCode.MakeInstruction(BPF_RET + BPF_K,
-                               SECCOMP_RET_ERRNO + aErrno,
-                               nullptr);
-}
-
-SandboxAssemblerImpl::NodePtr
-SandboxAssemblerImpl::RetKill()
-{
-  return mCode.MakeInstruction(BPF_RET + BPF_K,
-                               SECCOMP_RET_TRAP,
-                               nullptr);
-}
-
-} // namespace mozilla
deleted file mode 100644
--- a/security/sandbox/linux/SandboxAssembler.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_SandboxAssembler_h
-#define mozilla_SandboxAssembler_h
-
-#include <vector>
-
-#include "mozilla/Assertions.h"
-
-struct sock_filter;
-
-namespace mozilla {
-
-class SandboxAssembler {
-public:
-  class Condition {
-    friend class SandboxAssembler;
-    uint32_t mSyscallNr;
-    bool mCheckingArg;
-    uint8_t mArgChecked;
-    // This class retains a copy of the array, because C++11
-    // initializer_list isn't supported on all relevant platforms.
-    std::vector<uint32_t> mArgValues;
-  public:
-    // Match any instance of the given syscall, with any arguments.
-    explicit Condition(uint32_t aSyscallNr)
-      : mSyscallNr(aSyscallNr)
-      , mCheckingArg(false)
-    { }
-    // Match the syscall only if the given argument is one of the
-    // values in the array specified.  (If the argument isn't
-    // representable as uint32, the process is killed or signaled, as
-    // appropriate.)
-    template<size_t n>
-    Condition(uint32_t aSyscallNr, uint8_t aArgChecked,
-              const uint32_t (&aArgValues)[n])
-      : mSyscallNr(aSyscallNr)
-      , mCheckingArg(true)
-      , mArgChecked(aArgChecked)
-      , mArgValues(aArgValues, aArgValues + n)
-    {
-      MOZ_ASSERT(aArgChecked < sNumArgs);
-    }
-    // This isn't perf-critical, so a naive copy ctor is fine.
-    Condition(const Condition& aOther)
-    : mSyscallNr(aOther.mSyscallNr)
-    , mCheckingArg(aOther.mCheckingArg)
-    , mArgChecked(aOther.mArgChecked)
-    , mArgValues(aOther.mArgValues)
-    { }
-  };
-
-  // Allow syscalls matching this condition, if no earlier condition matched.
-  void Allow(const Condition& aCond) {
-    mRuleStack.push_back(std::make_pair(0, aCond));
-  }
-  // Cause syscalls matching this condition to fail with the given error, if
-  // no earlier condition matched.
-  void Deny(int aErrno, const Condition& aCond) {
-    MOZ_ASSERT(aErrno != 0);
-    mRuleStack.push_back(std::make_pair(aErrno, aCond));
-  }
-
-  void Compile(std::vector<sock_filter>* aProgram, bool aPrint = false);
-private:
-  std::vector<std::pair<int, Condition>> mRuleStack;
-
-  static const uint8_t sNumArgs = 6;
-};
-
-}
-
-#endif
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -1,502 +1,599 @@
 /* -*- 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 "SandboxFilter.h"
-#include "SandboxAssembler.h"
+#include "SandboxFilterUtil.h"
+#include "SandboxInternal.h"
+#include "SandboxLogging.h"
+
+#include "mozilla/UniquePtr.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <linux/ipc.h>
 #include <linux/net.h>
 #include <linux/prctl.h>
 #include <linux/sched.h>
 #include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
 #include <time.h>
 #include <unistd.h>
 
-#include "mozilla/ArrayUtils.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
 #include "sandbox/linux/services/linux_syscalls.h"
 
+using namespace sandbox::bpf_dsl;
+#define CASES SANDBOX_BPF_DSL_CASES
+
+// To avoid visual confusion between "ifdef ANDROID" and "ifndef ANDROID":
+#ifndef ANDROID
+#define DESKTOP
+#endif
+
+// This file defines the seccomp-bpf system call filter policies.
+// See also SandboxFilterUtil.h, for the CASES_FOR_* macros and
+// SandboxFilterBase::Evaluate{Socket,Ipc}Call.
+//
+// One important difference from how Chromium bpf_dsl filters are
+// normally interpreted: returning -ENOSYS from a Trap() handler
+// indicates an unexpected system call; SigSysHandler() in Sandbox.cpp
+// will detect this, request a crash dump, and terminate the process.
+// This does not apply to using Error(ENOSYS) in the policy, so that
+// can be used if returning an actual ENOSYS is needed.
+
 namespace mozilla {
 
-class SandboxFilterImpl : public SandboxAssembler
+// This class whitelists everything used by the sandbox itself, by the
+// core IPC code, by the crash reporter, or other core code.
+class SandboxPolicyCommon : public SandboxPolicyBase
 {
-public:
-  virtual void Build() = 0;
-  virtual ~SandboxFilterImpl() { }
-  void AllowThreadClone();
-};
-
-// Some helper macros to make the code that builds the filter more
-// readable, and to help deal with differences among architectures.
-
-#define SYSCALL_EXISTS(name) (defined(__NR_##name))
-
-#define SYSCALL(name) (Condition(__NR_##name))
-#if defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
-#define ARM_SYSCALL(name) (Condition(__ARM_NR_##name))
-#endif
-
-#define SYSCALL_WITH_ARG(name, arg, values...) ({ \
-  uint32_t argValues[] = { values };              \
-  Condition(__NR_##name, arg, argValues);         \
-})
+  static intptr_t BlockedSyscallTrap(const sandbox::arch_seccomp_data& aArgs,
+                                     void *aux)
+  {
+    MOZ_ASSERT(!aux);
+    return -ENOSYS;
+  }
 
-// Some architectures went through a transition from 32-bit to
-// 64-bit off_t and had to version all the syscalls that referenced
-// it; others (newer and/or 64-bit ones) didn't.  Adjust the
-// conditional as needed.
-#if SYSCALL_EXISTS(stat64)
-#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(versioned)
-#else
-#define SYSCALL_LARGEFILE(plain, versioned) SYSCALL(plain)
-#endif
-
-// i386 multiplexes all the socket-related interfaces into a single
-// syscall.
-#if SYSCALL_EXISTS(socketcall)
-#define SOCKETCALL(name, NAME) SYSCALL_WITH_ARG(socketcall, 0, SYS_##NAME)
-#else
-#define SOCKETCALL(name, NAME) SYSCALL(name)
-#endif
-
-// i386 multiplexes all the SysV-IPC-related interfaces into a single
-// syscall.
-#if SYSCALL_EXISTS(ipc)
-#define SYSVIPCCALL(name, NAME) SYSCALL_WITH_ARG(ipc, 0, NAME)
-#else
-#define SYSVIPCCALL(name, NAME) SYSCALL(name)
+#if defined(ANDROID) && ANDROID_VERSION < 16
+  // Bug 1093893: Translate tkill to tgkill for pthread_kill; fixed in
+  // bionic commit 10c8ce59a (in JB and up; API level 16 = Android 4.1).
+  static intptr_t TKillCompatTrap(const sandbox::arch_seccomp_data& aArgs,
+                                  void *aux)
+  {
+    return syscall(__NR_tgkill, getpid(), aArgs.args[0], aArgs.args[1]);
+  }
 #endif
 
-void SandboxFilterImpl::AllowThreadClone() {
-  // WARNING: s390 and cris pass the flags in a different arg -- see
-  // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
-  // don't support seccomp-bpf on those archs yet.
-  //
-  // The glibc source hasn't changed the thread creation clone flags
-  // since 2004, so this *should* be safe to hard-code.  Bionic's
-  // value has changed a few times, and has converged on the same one
-  // as glibc; allow any of them.
-  static const int flags_common = CLONE_VM | CLONE_FS | CLONE_FILES |
-    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
-  Allow(SYSCALL_WITH_ARG(clone, 0,
+public:
+  virtual ResultExpr InvalidSyscall() const override {
+    return Trap(BlockedSyscallTrap, nullptr);
+  }
+
+  virtual ResultExpr ClonePolicy() const {
+    // Allow use for simple thread creation (pthread_create) only.
+
+    // WARNING: s390 and cris pass the flags in the second arg -- see
+    // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
+    // don't support seccomp-bpf on those archs yet.
+    Arg<int> flags(0);
+
+    // The glibc source hasn't changed the thread creation clone flags
+    // since 2004, so this *should* be safe to hard-code.  Bionic's
+    // value has changed a few times, and has converged on the same one
+    // as glibc; allow any of them.
+    static const int flags_common = CLONE_VM | CLONE_FS | CLONE_FILES |
+      CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
+    static const int flags_modern = flags_common | CLONE_SETTLS |
+      CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
+
+    // Can't use CASES here because its decltype magic infers const
+    // int instead of regular int and bizarre voluminous errors issue
+    // forth from the depths of the standard library implementation.
+    return Switch(flags)
 #ifdef ANDROID
-                         flags_common | CLONE_DETACHED, // <= JB 4.2
-                         flags_common, // JB 4.3 or KK 4.4
+      .Case(flags_common | CLONE_DETACHED, Allow()) // <= JB 4.2
+      .Case(flags_common, Allow()) // JB 4.3 or KK 4.4
 #endif
-                         flags_common | CLONE_SETTLS // Android L or glibc
-                         | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID));
-}
+      .Case(flags_modern, Allow()) // Android L or glibc
+      .Default(InvalidSyscall());
+  }
 
-#ifdef MOZ_CONTENT_SANDBOX
-class SandboxFilterImplContent : public SandboxFilterImpl {
-protected:
-  virtual void Build() override;
-};
+  virtual ResultExpr PrctlPolicy() const {
+    // Note: this will probably need PR_SET_VMA if/when it's used on
+    // Android without being overridden by an allow-all policy, and
+    // the constant will need to be defined locally.
+    Arg<int> op(0);
+    return Switch(op)
+      .CASES((PR_GET_SECCOMP, // BroadcastSetThreadSandbox, etc.
+              PR_SET_NAME,    // Thread creation
+              PR_SET_DUMPABLE), // Crash reporting
+             Allow())
+      .Default(InvalidSyscall());
+  }
+
+  virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
+    switch (aCall) {
+    case SYS_RECVMSG:
+    case SYS_SENDMSG:
+      return Some(Allow());
+    default:
+      return Nothing();
+    }
+  }
 
-void
-SandboxFilterImplContent::Build() {
-  /* Most used system calls should be at the top of the whitelist
-   * for performance reasons. The whitelist BPF filter exits after
-   * processing any ALLOW_SYSCALL macro.
-   *
-   * How are those syscalls found?
-   * 1) via strace -p <child pid> or/and
-   * 2) the child will report which system call has been denied by seccomp-bpf,
-   *    just before exiting
-   * System call number to name mapping is found in:
-   * bionic/libc/kernel/arch-arm/asm/unistd.h
-   * or your libc's unistd.h/kernel headers.
-   *
-   * Current list order has been optimized through manual guess-work.
-   * It could be further optimized by analyzing the output of:
-   * 'strace -c -p <child pid>' for most used web apps.
-   */
+  virtual ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      // Timekeeping
+    case __NR_clock_gettime: {
+      Arg<clockid_t> clk_id(0);
+      return If(clk_id == CLOCK_MONOTONIC, Allow())
+        .ElseIf(clk_id == CLOCK_REALTIME, Allow())
+        .Else(InvalidSyscall());
+    }
+    case __NR_gettimeofday:
+#ifdef __NR_time
+    case __NR_time:
+#endif
+    case __NR_nanosleep:
+      return Allow();
+
+      // Thread synchronization
+    case __NR_futex:
+      // FIXME: This could be more restrictive....
+      return Allow();
+
+      // Asynchronous I/O
+    case __NR_epoll_wait:
+    case __NR_epoll_pwait:
+    case __NR_epoll_ctl:
+    case __NR_ppoll:
+    case __NR_poll:
+      return Allow();
+
+      // Used when requesting a crash dump.
+    case __NR_pipe:
+      return Allow();
 
-  Allow(SYSCALL(futex));
-  Allow(SOCKETCALL(recvmsg, RECVMSG));
-  Allow(SOCKETCALL(sendmsg, SENDMSG));
+      // Metadata of opened files
+    CASES_FOR_fstat:
+      return Allow();
+
+      // Simple I/O
+    case __NR_write:
+    case __NR_read:
+      return Allow();
+
+      // Memory mapping
+    CASES_FOR_mmap:
+    case __NR_munmap:
+      return Allow();
 
-  // mmap2 is a little different from most off_t users, because it's
-  // passed in a register (so it's a problem for even a "new" 32-bit
-  // arch) -- and the workaround, mmap2, passes a page offset instead.
-#if SYSCALL_EXISTS(mmap2)
-  Allow(SYSCALL(mmap2));
-#else
-  Allow(SYSCALL(mmap));
+      // Signal handling
+#if defined(ANDROID) || defined(MOZ_ASAN)
+    case __NR_sigaltstack:
+#endif
+    CASES_FOR_sigreturn:
+    CASES_FOR_sigprocmask:
+    CASES_FOR_sigaction:
+      return Allow();
+
+      // Send signals within the process (raise(), profiling, etc.)
+    case __NR_tgkill: {
+      Arg<pid_t> tgid(0);
+      return If(tgid == getpid(), Allow())
+        .Else(InvalidSyscall());
+    }
+
+#if defined(ANDROID) && ANDROID_VERSION < 16
+      // Polyfill with tgkill; see above.
+    case __NR_tkill:
+      return Trap(TKillCompatTrap, nullptr);
 #endif
 
-  Allow(SYSCALL(clock_gettime));
-  Allow(SYSCALL(epoll_wait));
-  Allow(SYSCALL(epoll_pwait));
-  Allow(SYSCALL(gettimeofday));
-  Allow(SYSCALL(read));
-  Allow(SYSCALL(write));
-  // 32-bit lseek is used, at least on Android, to implement ANSI fseek.
-#if SYSCALL_EXISTS(_llseek)
-  Allow(SYSCALL(_llseek));
+      // Yield
+    case __NR_sched_yield:
+      return Allow();
+
+      // Thread creation.
+    case __NR_clone:
+      return ClonePolicy();
+
+      // More thread creation.
+#ifdef __NR_set_robust_list
+    case __NR_set_robust_list:
+      return Allow();
 #endif
-  Allow(SYSCALL(lseek));
-  // Android also uses 32-bit ftruncate.
-  Allow(SYSCALL(ftruncate));
-#if SYSCALL_EXISTS(ftruncate64)
-  Allow(SYSCALL(ftruncate64));
+#ifdef ANDROID
+    case __NR_set_tid_address:
+      return Allow();
 #endif
 
-  /* ioctl() is for GL. Remove when GL proxy is implemented.
-   * Additionally ioctl() might be a place where we want to have
-   * argument filtering */
-  Allow(SYSCALL(ioctl));
-  Allow(SYSCALL(close));
-  Allow(SYSCALL(munmap));
-  Allow(SYSCALL(mprotect));
-  Allow(SYSCALL(writev));
-  Allow(SYSCALL(pread64));
-  AllowThreadClone();
-  Allow(SYSCALL(brk));
-#if SYSCALL_EXISTS(set_thread_area)
-  Allow(SYSCALL(set_thread_area));
+      // prctl
+    case __NR_prctl:
+      return PrctlPolicy();
+
+      // NSPR can call this when creating a thread, but it will accept a
+      // polite "no".
+    case __NR_getpriority:
+      // But if thread creation races with sandbox startup, that call
+      // could succeed, and then we get one of these:
+    case __NR_setpriority:
+      return Error(EACCES);
+
+      // Stack bounds are obtained via pthread_getattr_np, which calls
+      // this but doesn't actually need it:
+    case __NR_sched_getaffinity:
+      return Error(ENOSYS);
+
+      // Read own pid/tid.
+    case __NR_getpid:
+    case __NR_gettid:
+      return Allow();
+
+      // Discard capabilities
+    case __NR_close:
+      return Allow();
+
+      // Machine-dependent stuff
+#ifdef __arm__
+    case __ARM_NR_breakpoint:
+    case __ARM_NR_cacheflush:
+    case __ARM_NR_usr26: // FIXME: do we actually need this?
+    case __ARM_NR_usr32:
+    case __ARM_NR_set_tls:
+      return Allow();
 #endif
 
-  Allow(SYSCALL(getpid));
-  Allow(SYSCALL(gettid));
-  Allow(SYSCALL(getrusage));
-  Allow(SYSCALL(times));
-  Allow(SYSCALL(madvise));
-  Allow(SYSCALL(dup));
-  Allow(SYSCALL(nanosleep));
-  Allow(SYSCALL(poll));
-  Allow(SYSCALL(ppoll));
-  Allow(SYSCALL(openat));
-  Allow(SYSCALL(faccessat));
-  // select()'s arguments used to be passed by pointer as a struct.
-#if SYSCALL_EXISTS(_newselect)
-  Allow(SYSCALL(_newselect));
-#else
-  Allow(SYSCALL(select));
+      // Needed when being debugged:
+    case __NR_restart_syscall:
+      return Allow();
+
+      // Terminate threads or the process
+    case __NR_exit:
+    case __NR_exit_group:
+      return Allow();
+
+#ifdef MOZ_ASAN
+      // ASAN's error reporter wants to know if stderr is a tty.
+    case __NR_ioctl: {
+      Arg<int> fd(0);
+      return If(fd == STDERR_FILENO, Allow())
+        .Else(InvalidSyscall());
+    }
+
+      // ...and before compiler-rt r209773, it will call readlink on
+      // /proc/self/exe and use the cached value only if that fails:
+    case __NR_readlink:
+    case __NR_readlinkat:
+      return Error(ENOENT);
+
+      // ...and if it found an external symbolizer, it will try to run it:
+      // (See also bug 1081242 comment #7.)
+    CASES_FOR_stat:
+      return Error(ENOENT);
 #endif
-  Allow(SYSCALL(pselect6));
-  // Some archs used to have 16-bit uid/gid instead of 32-bit.
-#if SYSCALL_EXISTS(getuid32)
-  Allow(SYSCALL(getuid32));
-  Allow(SYSCALL(geteuid32));
-  Allow(SYSCALL(getgid32));
-  Allow(SYSCALL(getegid32));
-#else
-  Allow(SYSCALL(getuid));
-  Allow(SYSCALL(geteuid));
-  Allow(SYSCALL(getgid));
-  Allow(SYSCALL(getegid));
-#endif
-  // Some newer archs (e.g., x64 and x32) have only rt_sigreturn, but
-  // ARM has and uses both syscalls -- rt_sigreturn for SA_SIGINFO
-  // handlers and classic sigreturn otherwise.
-#if SYSCALL_EXISTS(sigreturn)
-  Allow(SYSCALL(sigreturn));
+
+    default:
+      return SandboxPolicyBase::EvaluateSyscall(sysno);
+    }
+  }
+};
+
+// The process-type-specific syscall rules start here:
+
+#ifdef MOZ_CONTENT_SANDBOX
+// The seccomp-bpf filter for content processes is not a true sandbox
+// on its own; its purpose is attack surface reduction and syscall
+// interception in support of a semantic sandboxing layer.  On B2G
+// this is the Android process permission model; on desktop,
+// namespaces and chroot() will be used.
+class ContentSandboxPolicy : public SandboxPolicyCommon {
+public:
+  ContentSandboxPolicy() { }
+  virtual ~ContentSandboxPolicy() { }
+  virtual ResultExpr PrctlPolicy() const override {
+    // Ideally this should be restricted to a whitelist, but content
+    // uses enough things that it's not trivial to determine it.
+    return Allow();
+  }
+  virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
+    switch(aCall) {
+    case SYS_RECVFROM:
+    case SYS_SENDTO:
+      return Some(Allow());
+
+    case SYS_SOCKETPAIR: {
+      // See bug 1066750.
+      if (!kSocketCallHasArgs) {
+        // We can't filter the args if the platform passes them by pointer.
+        return Some(Allow());
+      }
+      Arg<int> domain(0), type(1);
+      return Some(If(domain == AF_UNIX &&
+                     (type == SOCK_STREAM || type == SOCK_SEQPACKET), Allow())
+                  .Else(InvalidSyscall()));
+    }
+
+#ifdef ANDROID
+    case SYS_SOCKET:
+      return Some(Error(EACCES));
+#else // #ifdef DESKTOP
+    case SYS_RECV:
+    case SYS_SEND:
+    case SYS_SOCKET: // DANGEROUS
+    case SYS_CONNECT: // DANGEROUS
+    case SYS_SETSOCKOPT:
+    case SYS_GETSOCKNAME:
+    case SYS_GETPEERNAME:
+    case SYS_SHUTDOWN:
+      return Some(Allow());
 #endif
-  Allow(SYSCALL(rt_sigreturn));
-  Allow(SYSCALL_LARGEFILE(fcntl, fcntl64));
+    default:
+      return SandboxPolicyCommon::EvaluateSocketCall(aCall);
+    }
+  }
 
-  /* Must remove all of the following in the future, when no longer used */
-  /* open() is for some legacy APIs such as font loading. */
-  Allow(SYSCALL_LARGEFILE(fstat, fstat64));
-  Allow(SYSCALL_LARGEFILE(stat, stat64));
-  Allow(SYSCALL_LARGEFILE(lstat, lstat64));
-  Allow(SYSCALL_LARGEFILE(newfstatat, fstatat64));
-  Allow(SOCKETCALL(socketpair, SOCKETPAIR));
-  Deny(EACCES, SOCKETCALL(socket, SOCKET));
-  Allow(SYSCALL(open));
-  Deny(EINVAL, SYSCALL(readlink)); /* Workaround for bug 964455 */
-  Deny(EINVAL, SYSCALL(readlinkat)); /* Workaround for bug 964455 */
-  Allow(SYSCALL(prctl));
-  Allow(SYSCALL(access));
-  Allow(SYSCALL(fsync));
-  Allow(SYSCALL(msync));
-
-#if defined(ANDROID) && !defined(MOZ_MEMORY)
-  // Android's libc's realloc uses mremap.
-  Allow(SYSCALL(mremap));
+#ifdef DESKTOP
+  virtual Maybe<ResultExpr> EvaluateIpcCall(int aCall) const override {
+    switch(aCall) {
+      // These are a problem: SysV shared memory follows the Unix
+      // "same uid policy" and can't be restricted/brokered like file
+      // access.  But the graphics layer might not be using them
+      // anymore; this needs to be studied.
+    case SHMGET:
+    case SHMCTL:
+    case SHMAT:
+    case SHMDT:
+      return Some(Allow());
+    default:
+      return SandboxPolicyCommon::EvaluateIpcCall(aCall);
+    }
+  }
 #endif
 
-  /* Should remove all of the following in the future, if possible */
-  Allow(SYSCALL(getpriority));
-  Allow(SYSCALL(sched_get_priority_min));
-  Allow(SYSCALL(sched_get_priority_max));
-  Allow(SYSCALL(setpriority));
-  // rt_sigprocmask is passed the sigset_t size.  On older archs,
-  // sigprocmask is a compatibility shim that assumes the pre-RT size.
-#if SYSCALL_EXISTS(sigprocmask)
-  Allow(SYSCALL(sigprocmask));
+  virtual ResultExpr EvaluateSyscall(int sysno) const override {
+    switch(sysno) {
+      // Filesystem operations we need to get rid of; see bug 930258.
+    case __NR_open:
+    case __NR_openat:
+    case __NR_access:
+    case __NR_faccessat:
+    CASES_FOR_stat:
+    CASES_FOR_lstat:
+    CASES_FOR_fstatat:
+#ifdef DESKTOP
+      // Some if not all of these can probably be soft-failed or
+      // removed entirely; this needs to be studied.
+    case __NR_mkdir:
+    case __NR_rmdir:
+    case __NR_getcwd:
+    CASES_FOR_statfs:
+    case __NR_chmod:
+    case __NR_rename:
+    case __NR_symlink:
+    case __NR_quotactl:
+    case __NR_utimes:
 #endif
-  Allow(SYSCALL(rt_sigprocmask));
+      return Allow();
 
-  // Used by profiler.  Also used for raise(), which causes problems
-  // with Android KitKat abort(); see bug 1004832.
-  Allow(SYSCALL_WITH_ARG(tgkill, 0, uint32_t(getpid())));
+    case __NR_readlink:
+    case __NR_readlinkat:
+      // Workaround for bug 964455:
+      return Error(EINVAL);
+
+    CASES_FOR_select:
+    case __NR_pselect6:
+      return Allow();
 
-  Allow(SOCKETCALL(sendto, SENDTO));
-  Allow(SOCKETCALL(recvfrom, RECVFROM));
-  Allow(SYSCALL_LARGEFILE(getdents, getdents64));
-  Allow(SYSCALL(epoll_ctl));
-  Allow(SYSCALL(sched_yield));
-  Allow(SYSCALL(sched_getscheduler));
-  Allow(SYSCALL(sched_setscheduler));
-  Allow(SYSCALL(sched_getparam));
-  Allow(SYSCALL(sched_setparam));
-  Allow(SYSCALL(sigaltstack));
-  Allow(SYSCALL(pipe));
-  Allow(SYSCALL(set_tid_address));
+    CASES_FOR_getdents:
+    CASES_FOR_lseek:
+    CASES_FOR_ftruncate:
+    case __NR_writev:
+    case __NR_pread64:
+#ifdef DESKTOP
+    case __NR_readahead:
+#endif
+      return Allow();
+
+    case __NR_ioctl:
+      // ioctl() is for GL. Remove when GL proxy is implemented.
+      // Additionally ioctl() might be a place where we want to have
+      // argument filtering
+      return Allow();
 
-  /* Always last and always OK calls */
-  /* Architecture-specific very infrequently used syscalls */
-#if SYSCALL_EXISTS(sigaction)
-  Allow(SYSCALL(sigaction));
+    CASES_FOR_fcntl:
+      // Some fcntls have significant side effects like sending
+      // arbitrary signals, and there's probably nontrivial kernel
+      // attack surface; this should be locked down more if possible.
+      return Allow();
+
+    case __NR_mprotect:
+    case __NR_brk:
+    case __NR_madvise:
+#if defined(ANDROID) && !defined(MOZ_MEMORY)
+      // Android's libc's realloc uses mremap.
+    case __NR_mremap:
 #endif
-  Allow(SYSCALL(rt_sigaction));
-#ifdef ARM_SYSCALL
-  Allow(ARM_SYSCALL(breakpoint));
-  Allow(ARM_SYSCALL(cacheflush));
-  Allow(ARM_SYSCALL(usr26));
-  Allow(ARM_SYSCALL(usr32));
-  Allow(ARM_SYSCALL(set_tls));
+      return Allow();
+
+    case __NR_sigaltstack:
+      return Allow();
+
+#ifdef __NR_set_thread_area
+    case __NR_set_thread_area:
+      return Allow();
 #endif
 
-  /* restart_syscall is called internally, generally when debugging */
-  Allow(SYSCALL(restart_syscall));
+    case __NR_getrusage:
+    case __NR_times:
+      return Allow();
+
+    case __NR_dup:
+      return Allow();
+
+    CASES_FOR_getuid:
+    CASES_FOR_getgid:
+    CASES_FOR_geteuid:
+    CASES_FOR_getegid:
+      return Allow();
 
-  /* linux desktop is not as performance critical as mobile */
-  /* we can place desktop syscalls at the end */
-#ifndef ANDROID
-  Allow(SYSCALL(stat));
-  Allow(SYSCALL(getdents));
-  Allow(SYSCALL(lstat));
-#if SYSCALL_EXISTS(mmap2)
-  Allow(SYSCALL(mmap2));
-#else
-  Allow(SYSCALL(mmap));
-#endif
-  Allow(SYSCALL(openat));
-  Allow(SYSCALL(fcntl));
-  Allow(SYSCALL(fstat));
-  Allow(SYSCALL(readlink));
-  Allow(SOCKETCALL(getsockname, GETSOCKNAME));
-  Allow(SYSCALL(getuid));
-  Allow(SYSCALL(geteuid));
-  Allow(SYSCALL(mkdir));
-  Allow(SYSCALL(getcwd));
-  Allow(SYSCALL(readahead));
-  Allow(SYSCALL(pread64));
-  Allow(SYSCALL(statfs));
-#if SYSCALL_EXISTS(ugetrlimit)
-  Allow(SYSCALL(ugetrlimit));
-#else
-  Allow(SYSCALL(getrlimit));
+    case __NR_fsync:
+    case __NR_msync:
+      return Allow();
+
+    case __NR_getpriority:
+    case __NR_setpriority:
+    case __NR_sched_get_priority_min:
+    case __NR_sched_get_priority_max:
+    case __NR_sched_getscheduler:
+    case __NR_sched_setscheduler:
+    case __NR_sched_getparam:
+    case __NR_sched_setparam:
+#ifdef DESKTOP
+    case __NR_sched_getaffinity:
 #endif
-  Allow(SOCKETCALL(shutdown, SHUTDOWN));
-  Allow(SOCKETCALL(getpeername, GETPEERNAME));
-  Allow(SYSCALL(eventfd2));
-  Allow(SYSCALL(clock_getres));
-  Allow(SYSCALL(sysinfo));
-  Allow(SYSCALL(getresuid));
-  Allow(SYSCALL(umask));
-  Allow(SYSCALL(getresgid));
-  Allow(SYSCALL(poll));
-  Allow(SYSCALL(ppoll));
-  Allow(SYSCALL(openat));
-  Allow(SYSCALL(faccessat));
-  Allow(SYSCALL(inotify_init1));
-  Allow(SYSCALL(wait4));
-  Allow(SYSVIPCCALL(shmctl, SHMCTL));
-  Allow(SYSCALL(set_robust_list));
-  Allow(SYSCALL(rmdir));
-  Allow(SOCKETCALL(recvfrom, RECVFROM));
-  Allow(SYSVIPCCALL(shmdt, SHMDT));
-  Allow(SYSCALL(pipe2));
-  Allow(SOCKETCALL(setsockopt, SETSOCKOPT));
-  Allow(SYSVIPCCALL(shmat, SHMAT));
-  Allow(SYSCALL(set_tid_address));
-  Allow(SYSCALL(inotify_add_watch));
-  Allow(SYSCALL(rt_sigprocmask));
-  Allow(SYSVIPCCALL(shmget, SHMGET));
-#if SYSCALL_EXISTS(utimes)
-  Allow(SYSCALL(utimes));
-#else
-  Allow(SYSCALL(utime));
+      return Allow();
+
+#ifdef DESKTOP
+    case __NR_pipe2:
+      return Allow();
+
+    CASES_FOR_getrlimit:
+    case __NR_clock_getres:
+    case __NR_getresuid:
+    case __NR_getresgid:
+      return Allow();
+
+    case __NR_umask:
+    case __NR_kill:
+    case __NR_wait4:
+#ifdef __NR_arch_prctl
+    case __NR_arch_prctl:
 #endif
-#if SYSCALL_EXISTS(arch_prctl)
-  Allow(SYSCALL(arch_prctl));
-#endif
-  Allow(SYSCALL(sched_getaffinity));
-  /* We should remove all of the following in the future (possibly even more) */
-  Allow(SOCKETCALL(socket, SOCKET));
-  Allow(SYSCALL(chmod));
-  Allow(SYSCALL(execve));
-  Allow(SYSCALL(rename));
-  Allow(SYSCALL(symlink));
-  Allow(SOCKETCALL(connect, CONNECT));
-  Allow(SYSCALL(quotactl));
-  Allow(SYSCALL(kill));
-  Allow(SOCKETCALL(sendto, SENDTO));
+      return Allow();
+
+    case __NR_eventfd2:
+    case __NR_inotify_init1:
+    case __NR_inotify_add_watch:
+      return Allow();
 #endif
 
-  /* nsSystemInfo uses uname (and we cache an instance, so */
-  /* the info remains present even if we block the syscall) */
-  Allow(SYSCALL(uname));
-  Allow(SYSCALL(exit_group));
-  Allow(SYSCALL(exit));
+      // nsSystemInfo uses uname (and we cache an instance, so
+      // the info remains present even if we block the syscall)
+    case __NR_uname:
+#ifdef DESKTOP
+    case __NR_sysinfo:
+#endif
+      return Allow();
+
+    default:
+      return SandboxPolicyCommon::EvaluateSyscall(sysno);
+    }
+  }
+};
+
+UniquePtr<sandbox::bpf_dsl::Policy>
+GetContentSandboxPolicy()
+{
+  return UniquePtr<sandbox::bpf_dsl::Policy>(new ContentSandboxPolicy());
 }
 #endif // MOZ_CONTENT_SANDBOX
 
+
 #ifdef MOZ_GMP_SANDBOX
-class SandboxFilterImplGMP : public SandboxFilterImpl {
-protected:
-  virtual void Build() override;
+// Unlike for content, the GeckoMediaPlugin seccomp-bpf policy needs
+// to be an effective sandbox by itself, because we allow GMP on Linux
+// systems where that's the only sandboxing mechanism we can use.
+//
+// Be especially careful about what this policy allows.
+class GMPSandboxPolicy : public SandboxPolicyCommon {
+  static intptr_t OpenTrap(const sandbox::arch_seccomp_data& aArgs,
+                           void* aux)
+  {
+    auto plugin = static_cast<SandboxOpenedFile*>(aux);
+    const char* path;
+    int flags;
+
+    switch (aArgs.nr) {
+#ifdef __NR_open
+    case __NR_open:
+      path = reinterpret_cast<const char*>(aArgs.args[0]);
+      flags = static_cast<int>(aArgs.args[1]);
+      break;
+#endif
+    case __NR_openat:
+      // The path has to be absolute to match the pre-opened file (see
+      // assertion in ctor) so the dirfd argument is ignored.
+      path = reinterpret_cast<const char*>(aArgs.args[1]);
+      flags = static_cast<int>(aArgs.args[2]);
+      break;
+    default:
+      MOZ_CRASH("unexpected syscall number");
+    }
+
+    if ((flags & O_ACCMODE) != O_RDONLY) {
+      SANDBOX_LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
+                        path, flags);
+      return -ENOSYS;
+    }
+    if (strcmp(path, plugin->mPath) != 0) {
+      SANDBOX_LOG_ERROR("attempt to open file %s which is not the media plugin"
+                        " %s", path, plugin->mPath);
+      return -ENOSYS;
+    }
+    int fd = plugin->mFd.exchange(-1);
+    if (fd < 0) {
+      SANDBOX_LOG_ERROR("multiple opens of media plugin file unimplemented");
+      return -ENOSYS;
+    }
+    return fd;
+  }
+
+  SandboxOpenedFile* mPlugin;
+public:
+  explicit GMPSandboxPolicy(SandboxOpenedFile* aPlugin)
+  : mPlugin(aPlugin)
+  {
+    MOZ_ASSERT(aPlugin->mPath[0] == '/', "plugin path should be absolute");
+  }
+
+  virtual ~GMPSandboxPolicy() { }
+
+  virtual ResultExpr EvaluateSyscall(int sysno) const override {
+    switch (sysno) {
+      // Simulate opening the plugin file.
+#ifdef __NR_open
+    case __NR_open:
+#endif
+    case __NR_openat:
+      return Trap(OpenTrap, mPlugin);
+
+      // ipc::Shmem
+    case __NR_mprotect:
+      return Allow();
+    case __NR_madvise: {
+      Arg<int> advice(2);
+      return If(advice == MADV_DONTNEED, Allow())
+        .Else(InvalidSyscall());
+    }
+
+    default:
+      return SandboxPolicyCommon::EvaluateSyscall(sysno);
+    }
+  }
 };
 
-void SandboxFilterImplGMP::Build() {
-  // As for content processes, check the most common syscalls first.
-
-  Allow(SYSCALL_WITH_ARG(clock_gettime, 0, CLOCK_MONOTONIC, CLOCK_REALTIME));
-  Allow(SYSCALL(futex));
-  Allow(SYSCALL(gettimeofday));
-  Allow(SYSCALL(poll));
-  Allow(SYSCALL(write));
-  Allow(SYSCALL(read));
-  Allow(SYSCALL(epoll_wait));
-  Allow(SYSCALL(epoll_pwait));
-  Allow(SOCKETCALL(recvmsg, RECVMSG));
-  Allow(SOCKETCALL(sendmsg, SENDMSG));
-  Allow(SYSCALL(time));
-  Allow(SYSCALL(sched_yield));
-
-  // Nothing after this line is performance-critical.
-
-#if SYSCALL_EXISTS(mmap2)
-  Allow(SYSCALL(mmap2));
-#else
-  Allow(SYSCALL(mmap));
-#endif
-  Allow(SYSCALL_LARGEFILE(fstat, fstat64));
-  Allow(SYSCALL(munmap));
-
-  Allow(SYSCALL(getpid));
-  Allow(SYSCALL(gettid));
-
-  AllowThreadClone();
-
-  Allow(SYSCALL_WITH_ARG(prctl, 0, PR_GET_SECCOMP, PR_SET_NAME));
-
-#if SYSCALL_EXISTS(set_robust_list)
-  Allow(SYSCALL(set_robust_list));
-#endif
-
-  // NSPR can call this when creating a thread, but it will accept a
-  // polite "no".
-  Deny(EACCES, SYSCALL(getpriority));
-  // But if thread creation races with sandbox startup, that call
-  // could succeed, and then we get one of these:
-  Deny(EACCES, SYSCALL(setpriority));
+UniquePtr<sandbox::bpf_dsl::Policy>
+GetMediaSandboxPolicy(SandboxOpenedFile* aPlugin)
+{
+  return UniquePtr<sandbox::bpf_dsl::Policy>(new GMPSandboxPolicy(aPlugin));
+}
 
-  // Stack bounds are obtained via pthread_getattr_np, which calls
-  // this but doesn't actually need it:
-  Deny(ENOSYS, SYSCALL(sched_getaffinity));
-
-#ifdef MOZ_ASAN
-  Allow(SYSCALL(sigaltstack));
-  // ASAN's error reporter wants to know if stderr is a tty.
-  Deny(ENOTTY, SYSCALL_WITH_ARG(ioctl, 0, STDERR_FILENO));
-  // ...and before compiler-rt r209773, it will call readlink and use
-  // the cached value only if that fails:
-  Deny(ENOENT, SYSCALL(readlink));
-  // ...and if it found an external symbolizer, it will try to run it:
-  // (See also bug 1081242 comment #7.)
-  Deny(ENOENT, SYSCALL_LARGEFILE(stat, stat64));
-#endif
-
-  Allow(SYSCALL(mprotect));
-  Allow(SYSCALL_WITH_ARG(madvise, 2, MADV_DONTNEED));
-
-#if SYSCALL_EXISTS(sigreturn)
-  Allow(SYSCALL(sigreturn));
-#endif
-  Allow(SYSCALL(rt_sigreturn));
-
-  Allow(SYSCALL(restart_syscall));
-  Allow(SYSCALL(close));
-
-  // "Sleeping for 300 seconds" in debug crashes; possibly other uses.
-  Allow(SYSCALL(nanosleep));
-
-  // For the crash reporter:
-#if SYSCALL_EXISTS(sigprocmask)
-  Allow(SYSCALL(sigprocmask));
-#endif
-  Allow(SYSCALL(rt_sigprocmask));
-#if SYSCALL_EXISTS(sigaction)
-  Allow(SYSCALL(sigaction));
-#endif
-  Allow(SYSCALL(rt_sigaction));
-  Allow(SYSCALL(pipe));
-  Allow(SYSCALL_WITH_ARG(tgkill, 0, uint32_t(getpid())));
-  Allow(SYSCALL_WITH_ARG(prctl, 0, PR_SET_DUMPABLE));
-
-  // Note for when GMP is supported on an ARM platform: Add whichever
-  // of the ARM-specific syscalls are needed for this type of process.
-
-  Allow(SYSCALL(epoll_ctl));
-  Allow(SYSCALL(exit));
-  Allow(SYSCALL(exit_group));
-}
 #endif // MOZ_GMP_SANDBOX
 
-SandboxFilter::SandboxFilter(const sock_fprog** aStored, SandboxType aType,
-                             bool aVerbose)
-  : mStored(aStored)
-{
-  MOZ_ASSERT(*mStored == nullptr);
-  std::vector<struct sock_filter> filterVec;
-  SandboxFilterImpl *impl;
-
-  switch (aType) {
-  case kSandboxContentProcess:
-#ifdef MOZ_CONTENT_SANDBOX
-    impl = new SandboxFilterImplContent();
-#else
-    MOZ_CRASH("Content process sandboxing not supported in this build!");
-#endif
-    break;
-  case kSandboxMediaPlugin:
-#ifdef MOZ_GMP_SANDBOX
-    impl = new SandboxFilterImplGMP();
-#else
-    MOZ_CRASH("Gecko Media Plugin process sandboxing not supported in this"
-              " build!");
-#endif
-    break;
-  default:
-    MOZ_CRASH("Nonexistent sandbox type!");
-  }
-  impl->Build();
-  impl->Compile(&filterVec, aVerbose);
-  delete impl;
-
-  mProg = new sock_fprog;
-  mProg->len = filterVec.size();
-  mProg->filter = mFilter = new sock_filter[mProg->len];
-  for (size_t i = 0; i < mProg->len; ++i) {
-    mFilter[i] = filterVec[i];
-  }
-  *mStored = mProg;
 }
-
-SandboxFilter::~SandboxFilter()
-{
-  *mStored = nullptr;
-  delete[] mFilter;
-  delete mProg;
-}
-
-}
--- a/security/sandbox/linux/SandboxFilter.h
+++ b/security/sandbox/linux/SandboxFilter.h
@@ -2,34 +2,35 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_SandboxFilter_h
 #define mozilla_SandboxFilter_h
 
-struct sock_fprog;
-struct sock_filter;
+#include "mozilla/Atomics.h"
+#include "mozilla/UniquePtr.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+}
+}
 
 namespace mozilla {
 
-enum SandboxType {
-  kSandboxContentProcess,
-  kSandboxMediaPlugin
+#ifdef MOZ_CONTENT_SANDBOX
+UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy();
+#endif
+
+#ifdef MOZ_GMP_SANDBOX
+struct SandboxOpenedFile {
+  const char *mPath;
+  Atomic<int> mFd;
 };
 
-class SandboxFilter {
-  sock_filter *mFilter;
-  sock_fprog *mProg;
-  const sock_fprog **mStored;
-public:
-  // RAII: on construction, builds the filter and stores it in the
-  // provided variable (with optional logging); on destruction, frees
-  // the filter and nulls out the pointer.
-  SandboxFilter(const sock_fprog** aStored, SandboxType aBox,
-                bool aVerbose = false);
-  ~SandboxFilter();
-};
+UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(SandboxOpenedFile* aPlugin);
+#endif
 
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxFilterUtil.cpp
@@ -0,0 +1,111 @@
+/* -*- 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 "SandboxFilterUtil.h"
+
+#ifndef ANDROID
+#include <linux/ipc.h>
+#endif
+#include <linux/net.h>
+
+#include "mozilla/UniquePtr.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#ifndef SYS_ACCEPT4
+// Android's kernel headers don't define these.
+#define SYS_ACCEPT4  18
+#define SYS_RECVMMSG 19
+#define SYS_SENDMMSG 20
+#endif
+
+using namespace sandbox::bpf_dsl;
+#define CASES SANDBOX_BPF_DSL_CASES
+
+namespace mozilla {
+
+sandbox::bpf_dsl::ResultExpr
+SandboxPolicyBase::EvaluateSyscall(int aSysno) const {
+  switch (aSysno) {
+#ifdef __NR_socketcall
+    case __NR_socketcall: {
+      Arg<int> call(0);
+      UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
+      for (int i = SYS_SOCKET; i <= SYS_SENDMMSG; ++i) {
+        auto thisCase = EvaluateSocketCall(i);
+        // Optimize out cases that are equal to the default.
+        if (thisCase) {
+          acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
+        }
+      }
+      return acc->Default(InvalidSyscall());
+    }
+#ifndef ANDROID
+    case __NR_ipc: {
+      Arg<int> callAndVersion(0);
+      auto call = callAndVersion & 0xFFFF;
+      UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
+      for (int i = SEMOP; i <= DIPC; ++i) {
+        auto thisCase = EvaluateIpcCall(i);
+        // Optimize out cases that are equal to the default.
+        if (thisCase) {
+          acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
+        }
+      }
+      return acc->Default(InvalidSyscall());
+    }
+#endif // ANDROID
+#else // __NR_socketcall
+#define DISPATCH_SOCKETCALL(sysnum, socketnum)         \
+    case sysnum:                                       \
+      return EvaluateSocketCall(socketnum).valueOr(InvalidSyscall())
+      DISPATCH_SOCKETCALL(__NR_socket,      SYS_SOCKET);
+      DISPATCH_SOCKETCALL(__NR_bind,        SYS_BIND);
+      DISPATCH_SOCKETCALL(__NR_connect,     SYS_CONNECT);
+      DISPATCH_SOCKETCALL(__NR_listen,      SYS_LISTEN);
+      DISPATCH_SOCKETCALL(__NR_accept,      SYS_ACCEPT);
+      DISPATCH_SOCKETCALL(__NR_getsockname, SYS_GETSOCKNAME);
+      DISPATCH_SOCKETCALL(__NR_getpeername, SYS_GETPEERNAME);
+      DISPATCH_SOCKETCALL(__NR_socketpair,  SYS_SOCKETPAIR);
+#ifdef __NR_send
+      DISPATCH_SOCKETCALL(__NR_send,        SYS_SEND);
+      DISPATCH_SOCKETCALL(__NR_recv,        SYS_RECV);
+#endif // __NR_send
+      DISPATCH_SOCKETCALL(__NR_sendto,      SYS_SENDTO);
+      DISPATCH_SOCKETCALL(__NR_recvfrom,    SYS_RECVFROM);
+      DISPATCH_SOCKETCALL(__NR_shutdown,    SYS_SHUTDOWN);
+      DISPATCH_SOCKETCALL(__NR_setsockopt,  SYS_SETSOCKOPT);
+      DISPATCH_SOCKETCALL(__NR_getsockopt,  SYS_GETSOCKOPT);
+      DISPATCH_SOCKETCALL(__NR_sendmsg,     SYS_SENDMSG);
+      DISPATCH_SOCKETCALL(__NR_recvmsg,     SYS_RECVMSG);
+      DISPATCH_SOCKETCALL(__NR_accept4,     SYS_ACCEPT4);
+      DISPATCH_SOCKETCALL(__NR_recvmmsg,    SYS_RECVMMSG);
+      DISPATCH_SOCKETCALL(__NR_sendmmsg,    SYS_SENDMMSG);
+#undef DISPATCH_SOCKETCALL
+#ifndef ANDROID
+#define DISPATCH_SYSVCALL(sysnum, ipcnum)         \
+    case sysnum:                                  \
+      return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
+      DISPATCH_SYSVCALL(__NR_semop,       SEMOP);
+      DISPATCH_SYSVCALL(__NR_semget,      SEMGET);
+      DISPATCH_SYSVCALL(__NR_semctl,      SEMCTL);
+      DISPATCH_SYSVCALL(__NR_semtimedop,  SEMTIMEDOP);
+      DISPATCH_SYSVCALL(__NR_msgsnd,      MSGSND);
+      DISPATCH_SYSVCALL(__NR_msgrcv,      MSGRCV);
+      DISPATCH_SYSVCALL(__NR_msgget,      MSGGET);
+      DISPATCH_SYSVCALL(__NR_msgctl,      MSGCTL);
+      DISPATCH_SYSVCALL(__NR_shmat,       SHMAT);
+      DISPATCH_SYSVCALL(__NR_shmdt,       SHMDT);
+      DISPATCH_SYSVCALL(__NR_shmget,      SHMGET);
+      DISPATCH_SYSVCALL(__NR_shmctl,      SHMCTL);
+#undef DISPATCH_SYSVCALL
+#endif // ANDROID
+#endif // __NR_socketcall
+  default:
+    return InvalidSyscall();
+  }
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/security/sandbox/linux/SandboxFilterUtil.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SandboxFilterUtil_h
+#define mozilla_SandboxFilterUtil_h
+
+// This header file exists to hold helper code for SandboxFilter.cpp,
+// to make that file easier to read for anyone trying to understand
+// the filter policy.  It's mostly about smoothing out differences
+// between different Linux architectures.
+
+#include "mozilla/Maybe.h"
+#include "sandbox/linux/services/linux_syscalls.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+
+namespace mozilla {
+
+// This class handles syscalls for BSD socket and SysV IPC operations.
+// On 32-bit x86 they're multiplexed via socketcall(2) and ipc(2),
+// respectively; on most other architectures they're individual system
+// calls. It translates the syscalls into socketcall/ipc selector
+// values, because those are defined (even if not used) for all
+// architectures.
+//
+// This EvaluateSyscall() routine always returns InvalidSyscall() for
+// everything else.  It's assumed that subclasses will be implementing
+// a whitelist policy, so they can handle what they're whitelisting
+// and then defer to this class in the default case.
+class SandboxPolicyBase : public sandbox::bpf_dsl::Policy
+{
+public:
+  using ResultExpr = sandbox::bpf_dsl::ResultExpr;
+
+  virtual ResultExpr EvaluateSyscall(int aSysno) const override;
+  virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const {
+    return Nothing();
+  }
+#ifndef ANDROID
+  // Android doesn't use SysV IPC (and doesn't define the selector
+  // constants in its headers), so this isn't implemented there.
+  virtual Maybe<ResultExpr> EvaluateIpcCall(int aCall) const {
+    return Nothing();
+  }
+#endif
+
+#ifdef __NR_socketcall
+  // socketcall(2) takes the actual call's arguments via a pointer, so
+  // seccomp-bpf can't inspect them; ipc(2) takes them at different indices.
+  static const bool kSocketCallHasArgs = false;
+  static const bool kIpcCallNormalArgs = false;
+#else
+  // Otherwise, the bpf_dsl Arg<> class can be used normally.
+  static const bool kSocketCallHasArgs = true;
+  static const bool kIpcCallNormalArgs = true;
+#endif
+};
+
+} // namespace mozilla
+
+// "Machine independent" pseudo-syscall numbers, to deal with arch
+// dependencies.  (Most 32-bit archs started with 32-bit off_t; older
+// archs started with 16-bit uid_t/gid_t; 32-bit registers can't hold
+// a 64-bit offset for mmap; and so on.)
+//
+// For some of these, the "old" syscalls are also in use in some
+// cases; see, e.g., the handling of RT vs. non-RT signal syscalls.
+
+#ifdef __NR_mmap2
+#define CASES_FOR_mmap   case __NR_mmap2
+#else
+#define CASES_FOR_mmap   case __NR_mmap
+#endif
+
+#ifdef __NR_getuid32
+#define CASES_FOR_getuid   case __NR_getuid32
+#define CASES_FOR_getgid   case __NR_getgid32
+#define CASES_FOR_geteuid   case __NR_geteuid32
+#define CASES_FOR_getegid   case __NR_getegid32
+#define CASES_FOR_getresuid   case __NR_getresuid32
+#define CASES_FOR_getresgid   case __NR_getresgid32
+// The set*id syscalls are omitted; we'll probably never need to allow them.
+#else
+#define CASES_FOR_getuid   case __NR_getuid
+#define CASES_FOR_getgid   case __NR_getgid
+#define CASES_FOR_geteuid   case __NR_geteuid
+#define CASES_FOR_getegid   case __NR_getegid
+#define CASES_FOR_getresuid   case __NR_getresuid
+#define CASES_FOR_getresgid   case __NR_getresgid
+#endif
+
+#ifdef __NR_stat64
+#define CASES_FOR_stat   case __NR_stat64
+#define CASES_FOR_lstat   case __NR_lstat64
+#define CASES_FOR_fstat   case __NR_fstat64
+#define CASES_FOR_fstatat   case __NR_fstatat64
+#define CASES_FOR_statfs   case __NR_statfs64
+#define CASES_FOR_fcntl   case __NR_fcntl64
+// We're using the 32-bit version on 32-bit desktop for some reason.
+#define CASES_FOR_getdents   case __NR_getdents64: case __NR_getdents
+// FIXME: we might not need the compat cases for these on non-Android:
+#define CASES_FOR_lseek   case __NR_lseek: case __NR__llseek
+#define CASES_FOR_ftruncate   case __NR_ftruncate: case __NR_ftruncate64
+#else
+#define CASES_FOR_stat   case __NR_stat
+#define CASES_FOR_lstat   case __NR_lstat
+#define CASES_FOR_fstatat   case __NR_newfstatat
+#define CASES_FOR_fstat   case __NR_fstat
+#define CASES_FOR_statfs   case __NR_statfs
+#define CASES_FOR_fcntl   case __NR_fcntl
+#define CASES_FOR_getdents   case __NR_getdents
+#define CASES_FOR_lseek   case __NR_lseek
+#define CASES_FOR_ftruncate   case __NR_ftruncate
+#endif
+
+#ifdef __NR_sigprocmask
+#define CASES_FOR_sigprocmask   case __NR_sigprocmask: case __NR_rt_sigprocmask
+#define CASES_FOR_sigaction   case __NR_sigaction: case __NR_rt_sigaction
+#define CASES_FOR_sigreturn   case __NR_sigreturn: case __NR_rt_sigreturn
+#else
+#define CASES_FOR_sigprocmask   case __NR_rt_sigprocmask
+#define CASES_FOR_sigaction   case __NR_rt_sigaction
+#define CASES_FOR_sigreturn   case __NR_rt_sigreturn
+#endif
+
+#ifdef __NR__newselect
+#define CASES_FOR_select   case __NR__newselect
+#else
+#define CASES_FOR_select   case __NR_select
+#endif
+
+#ifdef __NR_ugetrlimit
+#define CASES_FOR_getrlimit   case __NR_ugetrlimit
+#else
+#define CASES_FOR_getrlimit   case __NR_getrlimit
+#endif
+
+#endif // mozilla_SandboxFilterUtil_h
--- a/security/sandbox/linux/moz.build
+++ b/security/sandbox/linux/moz.build
@@ -42,28 +42,30 @@ SOURCES += [
     '../chromium/base/threading/thread_collision_warner.cc',
     '../chromium/base/threading/thread_id_name_manager.cc',
     '../chromium/base/threading/thread_local_posix.cc',
     '../chromium/base/threading/thread_restrictions.cc',
     '../chromium/base/time/time.cc',
     '../chromium/base/time/time_posix.cc',
     '../chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc',
     '../chromium/sandbox/linux/bpf_dsl/dump_bpf.cc',
+    '../chromium/sandbox/linux/bpf_dsl/policy.cc',
     '../chromium/sandbox/linux/bpf_dsl/policy_compiler.cc',
     '../chromium/sandbox/linux/seccomp-bpf/basicblock.cc',
     '../chromium/sandbox/linux/seccomp-bpf/codegen.cc',
     '../chromium/sandbox/linux/seccomp-bpf/die.cc',
     '../chromium/sandbox/linux/seccomp-bpf/errorcode.cc',
     '../chromium/sandbox/linux/seccomp-bpf/syscall.cc',
     '../chromium/sandbox/linux/seccomp-bpf/syscall_iterator.cc',
+    '../chromium/sandbox/linux/seccomp-bpf/trap.cc',
     'LinuxCapabilities.cpp',
     'Sandbox.cpp',
-    'SandboxAssembler.cpp',
     'SandboxChroot.cpp',
     'SandboxFilter.cpp',
+    'SandboxFilterUtil.cpp',
     'SandboxUtil.cpp',
 ]
 
 # gcc lto likes to put the top level asm in syscall.cc in a different partition
 # from the function using it which breaks the build.  Work around that by
 # forcing there to be only one partition.
 if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']:
     LDFLAGS += ['--param lto-partitions=1']
--- a/tools/profiler/ProfileEntry.cpp
+++ b/tools/profiler/ProfileEntry.cpp
@@ -395,22 +395,16 @@ UniqueStacks::Stack UniqueStacks::BeginS
 UniqueStacks::UniqueStacks(JSRuntime* aRuntime)
  : mRuntime(aRuntime)
  , mFrameCount(0)
 {
   mFrameTableWriter.StartBareList();
   mStackTableWriter.StartBareList();
 }
 
-UniqueStacks::~UniqueStacks()
-{
-  mFrameTableWriter.EndBareList();
-  mStackTableWriter.EndBareList();
-}
-
 uint32_t UniqueStacks::GetOrAddStackIndex(const StackKey& aStack)
 {
   uint32_t index;
   if (mStackToIndexMap.Get(aStack, &index)) {
     MOZ_ASSERT(index < mStackToIndexMap.Count());
     return index;
   }
 
@@ -457,24 +451,26 @@ uint32_t UniqueStacks::LookupJITFrameDep
   return 0;
 }
 
 void UniqueStacks::AddJITFrameDepth(void* aAddr, unsigned depth)
 {
   mJITFrameDepthMap.Put(aAddr, depth);
 }
 
-void UniqueStacks::SpliceFrameTableElements(SpliceableJSONWriter& aWriter) const
+void UniqueStacks::SpliceFrameTableElements(SpliceableJSONWriter& aWriter)
 {
-  aWriter.Splice(mFrameTableWriter.WriteFunc());
+  mFrameTableWriter.EndBareList();
+  aWriter.TakeAndSplice(mFrameTableWriter.WriteFunc());
 }
 
-void UniqueStacks::SpliceStackTableElements(SpliceableJSONWriter& aWriter) const
+void UniqueStacks::SpliceStackTableElements(SpliceableJSONWriter& aWriter)
 {
-  aWriter.Splice(mStackTableWriter.WriteFunc());
+  mStackTableWriter.EndBareList();
+  aWriter.TakeAndSplice(mStackTableWriter.WriteFunc());
 }
 
 void UniqueStacks::StreamStack(const StackKey& aStack)
 {
   // Schema:
   //   [prefix, frame]
 
   mStackTableWriter.StartArrayElement();
--- a/tools/profiler/ProfileEntry.h
+++ b/tools/profiler/ProfileEntry.h
@@ -82,22 +82,18 @@ private:
 
 class UniqueJSONStrings
 {
 public:
   UniqueJSONStrings() {
     mStringTableWriter.StartBareList();
   }
 
-  ~UniqueJSONStrings() {
-    mStringTableWriter.EndBareList();
-  }
-
-  void SpliceStringTableElements(SpliceableJSONWriter& aWriter) const {
-    aWriter.Splice(mStringTableWriter.WriteFunc());
+  void SpliceStringTableElements(SpliceableJSONWriter& aWriter) {
+    aWriter.TakeAndSplice(mStringTableWriter.WriteFunc());
   }
 
   void WriteProperty(mozilla::JSONWriter& aWriter, const char* aName, const char* aStr) {
     aWriter.IntProperty(aName, GetOrAddIndex(aStr));
   }
 
   void WriteElement(mozilla::JSONWriter& aWriter, const char* aStr) {
     aWriter.IntElement(GetOrAddIndex(aStr));
@@ -188,23 +184,22 @@ public:
     uint32_t GetOrAddIndex() const;
 
   private:
     UniqueStacks& mUniqueStacks;
     StackKey mStack;
   };
 
   explicit UniqueStacks(JSRuntime* aRuntime);
-  ~UniqueStacks();
 
   Stack BeginStack(const OnStackFrameKey& aRoot);
   uint32_t LookupJITFrameDepth(void* aAddr);
   void AddJITFrameDepth(void* aAddr, unsigned depth);
-  void SpliceFrameTableElements(SpliceableJSONWriter& aWriter) const;
-  void SpliceStackTableElements(SpliceableJSONWriter& aWriter) const;
+  void SpliceFrameTableElements(SpliceableJSONWriter& aWriter);
+  void SpliceStackTableElements(SpliceableJSONWriter& aWriter);
 
 private:
   uint32_t GetOrAddFrameIndex(const OnStackFrameKey& aFrame);
   uint32_t GetOrAddStackIndex(const StackKey& aStack);
   void StreamFrame(const OnStackFrameKey& aFrame);
   void StreamStack(const StackKey& aStack);
 
 public:
--- a/tools/profiler/ProfileJSONWriter.cpp
+++ b/tools/profiler/ProfileJSONWriter.cpp
@@ -53,36 +53,63 @@ ChunkedJSONWriteFunc::CopyData() const
     memcpy(ptr, mChunkList[i].get(), len);
     ptr += len;
   }
   *ptr = '\0';
   return c;
 }
 
 void
+ChunkedJSONWriteFunc::Take(ChunkedJSONWriteFunc&& aOther)
+{
+  for (size_t i = 0; i < aOther.mChunkList.length(); i++) {
+    MOZ_ALWAYS_TRUE(mChunkLengths.append(aOther.mChunkLengths[i]));
+    MOZ_ALWAYS_TRUE(mChunkList.append(mozilla::Move(aOther.mChunkList[i])));
+  }
+  mChunkPtr = mChunkList.back().get() + mChunkLengths.back();
+  mChunkEnd = mChunkPtr;
+  aOther.mChunkPtr = nullptr;
+  aOther.mChunkEnd = nullptr;
+  aOther.mChunkList.clear();
+  aOther.mChunkLengths.clear();
+}
+
+void
 ChunkedJSONWriteFunc::AllocChunk(size_t aChunkSize)
 {
   MOZ_ASSERT(mChunkLengths.length() == mChunkList.length());
   mozilla::UniquePtr<char[]> newChunk = mozilla::MakeUnique<char[]>(aChunkSize);
   mChunkPtr = newChunk.get();
   mChunkEnd = mChunkPtr + aChunkSize;
   *mChunkPtr = '\0';
   MOZ_ALWAYS_TRUE(mChunkLengths.append(0));
   MOZ_ALWAYS_TRUE(mChunkList.append(mozilla::Move(newChunk)));
 }
 
 void
-SpliceableJSONWriter::Splice(const ChunkedJSONWriteFunc* aFunc)
+SpliceableJSONWriter::TakeAndSplice(ChunkedJSONWriteFunc* aFunc)
 {
   Separator();
   for (size_t i = 0; i < aFunc->mChunkList.length(); i++) {
     WriteFunc()->Write(aFunc->mChunkList[i].get());
   }
+  aFunc->mChunkPtr = nullptr;
+  aFunc->mChunkEnd = nullptr;
+  aFunc->mChunkList.clear();
+  aFunc->mChunkLengths.clear();
   mNeedComma[mDepth] = true;
 }
 
 void
 SpliceableJSONWriter::Splice(const char* aStr)
 {
   Separator();
   WriteFunc()->Write(aStr);
   mNeedComma[mDepth] = true;
 }
+
+void
+SpliceableChunkedJSONWriter::TakeAndSplice(ChunkedJSONWriteFunc* aFunc)
+{
+  Separator();
+  WriteFunc()->Take(mozilla::Move(*aFunc));
+  mNeedComma[mDepth] = true;
+}
--- a/tools/profiler/ProfileJSONWriter.h
+++ b/tools/profiler/ProfileJSONWriter.h
@@ -24,18 +24,26 @@ class ChunkedJSONWriteFunc : public mozi
 {
 public:
   friend class SpliceableJSONWriter;
 
   ChunkedJSONWriteFunc() {
     AllocChunk(kChunkSize);
   }
 
+  bool IsEmpty() const {
+    MOZ_ASSERT_IF(!mChunkPtr, !mChunkEnd &&
+                              mChunkList.length() == 0 &&
+                              mChunkLengths.length() == 0);
+    return !mChunkPtr;
+  }
+
   void Write(const char* aStr) override;
   mozilla::UniquePtr<char[]> CopyData() const;
+  void Take(ChunkedJSONWriteFunc&& aOther);
 
 private:
   void AllocChunk(size_t aChunkSize);
 
   static const size_t kChunkSize = 4096 * 512;
 
   // Pointer for writing inside the current chunk.
   //
@@ -88,23 +96,31 @@ public:
   void NullElements(uint32_t aCount) {
     for (uint32_t i = 0; i < aCount; i++) {
       NullElement();
     }
   }
 
   void Splice(const ChunkedJSONWriteFunc* aFunc);
   void Splice(const char* aStr);
+
+  // Takes the chunks from aFunc and write them. If move is not possible
+  // (e.g., using OStreamJSONWriteFunc), aFunc's chunks are copied and its
+  // storage cleared.
+  virtual void TakeAndSplice(ChunkedJSONWriteFunc* aFunc);
 };
 
 class SpliceableChunkedJSONWriter : public SpliceableJSONWriter
 {
 public:
   explicit SpliceableChunkedJSONWriter()
     : SpliceableJSONWriter(mozilla::MakeUnique<ChunkedJSONWriteFunc>())
   { }
 
   ChunkedJSONWriteFunc* WriteFunc() const {
     return static_cast<ChunkedJSONWriteFunc*>(JSONWriter::WriteFunc());
   }
+
+  // Adopts the chunks from aFunc without copying.
+  virtual void TakeAndSplice(ChunkedJSONWriteFunc* aFunc) override;
 };
 
 #endif // PROFILEJSONWRITER_H
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -140,24 +140,25 @@ ContentCache::AssignContent(const Conten
   mSelection = aOther.mSelection;
   mCaret = aOther.mCaret;
   mTextRectArray = aOther.mTextRectArray;
   mEditorRect = aOther.mEditorRect;
 
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCache: 0x%p (mIsChrome=%s) AssignContent(aNotification=%s), "
      "Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
-     "mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s }, "
+     "mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s, mRect=%s }, "
      "mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ mStart=%u, "
      "mRects.Length()=%u }, mEditorRect=%s",
      this, GetBoolName(mIsChrome), GetNotificationName(aNotification),
      mText.Length(), mSelection.mAnchor, mSelection.mFocus,
      GetWritingModeName(mSelection.mWritingMode).get(),
      GetRectText(mSelection.mAnchorCharRect).get(),
-     GetRectText(mSelection.mFocusCharRect).get(), mCaret.mOffset,
+     GetRectText(mSelection.mFocusCharRect).get(),
+     GetRectText(mSelection.mRect).get(), mCaret.mOffset,
      GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
      mTextRectArray.mRects.Length(), GetRectText(mEditorRect).get()));
 }
 
 void
 ContentCache::Clear()
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
@@ -590,16 +591,17 @@ ContentCache::CacheTextRects(nsIWidget* 
   // CacheTextRects() must be called in content process.
   if (NS_WARN_IF(mIsChrome)) {
     return false;
   }
 
   mTextRectArray.Clear();
   mSelection.mAnchorCharRect.SetEmpty();
   mSelection.mFocusCharRect.SetEmpty();
+  mSelection.mRect.SetEmpty();
 
   if (NS_WARN_IF(!mSelection.IsValid())) {
     return false;
   }
 
   // Retrieve text rects in composition string if there is.
   nsRefPtr<TextComposition> textComposition =
     IMEStateManager::GetTextCompositionFor(aWidget);
@@ -648,25 +650,42 @@ ContentCache::CacheTextRects(nsIWidget* 
       MOZ_LOG(sContentCacheLog, LogLevel::Error,
         ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
          "couldn't retrieve text rect at focus of selection (%u)",
          this, GetBoolName(mIsChrome), mSelection.mFocus));
     }
     mSelection.mFocusCharRect = charRect;
   }
 
+  if (!mSelection.Collapsed()) {
+    nsEventStatus status = nsEventStatus_eIgnore;
+    WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget);
+    textRect.InitForQueryTextRect(mSelection.StartOffset(),
+                                  mSelection.Length());
+    aWidget->DispatchEvent(&textRect, status);
+    if (NS_WARN_IF(!textRect.mSucceeded)) {
+      MOZ_LOG(sContentCacheLog, LogLevel::Error,
+        ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
+         "couldn't retrieve text rect of whole selected text",
+         this, GetBoolName(mIsChrome)));
+    } else {
+      mSelection.mRect = textRect.mReply.mRect;
+    }
+  }
+
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), Succeeded, "
      "mText.Length()=%u, mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
      "mSelection={ mAnchor=%u, mAnchorCharRect=%s, mFocus=%u, "
-     "mFocusCharRect=%s }",
+     "mFocusCharRect=%s, mRect=%s }",
      this, GetBoolName(mIsChrome), mText.Length(), mTextRectArray.mStart,
      mTextRectArray.mRects.Length(), mSelection.mAnchor,
      GetRectText(mSelection.mAnchorCharRect).get(), mSelection.mFocus,
-     GetRectText(mSelection.mFocusCharRect).get()));
+     GetRectText(mSelection.mFocusCharRect).get(),
+     GetRectText(mSelection.mRect).get()));
   return true;
 }
 
 void
 ContentCache::SetSelection(nsIWidget* aWidget,
                            uint32_t aStartOffset,
                            uint32_t aLength,
                            bool aReversed,
@@ -736,16 +755,23 @@ ContentCache::GetUnionTextRects(uint32_t
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCache: 0x%p (mIsChrome=%s) GetUnionTextRects(aOffset=%u, "
      "aLength=%u), mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
      "mSelection={ mAnchor=%u, mFocus=%u }",
      this, GetBoolName(mIsChrome), aOffset, aLength,
      mTextRectArray.mStart, mTextRectArray.mRects.Length(),
      mSelection.mAnchor, mSelection.mFocus));
 
+  if (!mSelection.Collapsed() &&
+      aOffset == mSelection.StartOffset() && aLength == mSelection.Length()) {
+    NS_WARN_IF(mSelection.mRect.IsEmpty());
+    aUnionTextRect = mSelection.mRect;
+    return !aUnionTextRect.IsEmpty();
+  }
+
   if (aLength == 1) {
     if (aOffset == mSelection.mAnchor) {
       NS_WARN_IF(mSelection.mAnchorCharRect.IsEmpty());
       aUnionTextRect = mSelection.mAnchorCharRect;
       return !aUnionTextRect.IsEmpty();
     }
     if (aOffset == mSelection.mFocus) {
       NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -165,28 +165,32 @@ private:
     uint32_t mFocus;
 
     WritingMode mWritingMode;
 
     // Character rects at next character of mAnchor and mFocus.
     LayoutDeviceIntRect mAnchorCharRect;
     LayoutDeviceIntRect mFocusCharRect;
 
+    // Whole rect of selected text. This is empty if the selection is collapsed.
+    LayoutDeviceIntRect mRect;
+
     Selection()
       : mAnchor(UINT32_MAX)
       , mFocus(UINT32_MAX)
     {
     }
 
     void Clear()
     {
       mAnchor = mFocus = UINT32_MAX;
       mWritingMode = WritingMode();
       mAnchorCharRect.SetEmpty();
       mFocusCharRect.SetEmpty();
+      mRect.SetEmpty();
     }
 
     bool IsValid() const
     {
       return mAnchor != UINT32_MAX && mFocus != UINT32_MAX;
     }
     bool Collapsed() const
     {
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -802,31 +802,33 @@ struct ParamTraits<mozilla::ContentCache
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mText);
     WriteParam(aMsg, aParam.mSelection.mAnchor);
     WriteParam(aMsg, aParam.mSelection.mFocus);
     WriteParam(aMsg, aParam.mSelection.mWritingMode);
     WriteParam(aMsg, aParam.mSelection.mAnchorCharRect);
     WriteParam(aMsg, aParam.mSelection.mFocusCharRect);
+    WriteParam(aMsg, aParam.mSelection.mRect);
     WriteParam(aMsg, aParam.mCaret.mOffset);
     WriteParam(aMsg, aParam.mCaret.mRect);
     WriteParam(aMsg, aParam.mTextRectArray.mStart);
     WriteParam(aMsg, aParam.mTextRectArray.mRects);
     WriteParam(aMsg, aParam.mEditorRect);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     return ReadParam(aMsg, aIter, &aResult->mText) &&
            ReadParam(aMsg, aIter, &aResult->mSelection.mAnchor) &&
            ReadParam(aMsg, aIter, &aResult->mSelection.mFocus) &&
            ReadParam(aMsg, aIter, &aResult->mSelection.mWritingMode) &&
            ReadParam(aMsg, aIter, &aResult->mSelection.mAnchorCharRect) &&
            ReadParam(aMsg, aIter, &aResult->mSelection.mFocusCharRect) &&
+           ReadParam(aMsg, aIter, &aResult->mSelection.mRect) &&
            ReadParam(aMsg, aIter, &aResult->mCaret.mOffset) &&
            ReadParam(aMsg, aIter, &aResult->mCaret.mRect) &&
            ReadParam(aMsg, aIter, &aResult->mTextRectArray.mStart) &&
            ReadParam(aMsg, aIter, &aResult->mTextRectArray.mRects) &&
            ReadParam(aMsg, aIter, &aResult->mEditorRect);
   }
 };
 
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -60,19 +60,16 @@ EXPORTS += [
     'nsTraceRefcnt.h',
     'nsWeakPtr.h',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     EXPORTS += [
         'nsWindowsHelpers.h',
     ]
-    if CONFIG['MOZ_DEBUG']:
-        EXPORTS += ['pure.h']
-        SOURCES += ['pure_api.c']
 
 EXPORTS.mozilla += [
     'AvailableMemoryTracker.h',
     'ClearOnShutdown.h',
     'CountingAllocatorBase.h',
     'CycleCollectedJSRuntime.h',
     'Debug.h',
     'DebuggerOnGCRunnable.h',
deleted file mode 100644
--- a/xpcom/base/pure.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Header file of Pure API function declarations.
- *
- * Explicitly no copyright.
- * You may recompile and redistribute these definitions as required.
- *
- * Version 1.0
- */
-
-#if defined(c_plusplus) || defined(__cplusplus)
-extern "C" {
-#endif
-
-#define PURE_H_VERSION 1
-
-//////////////////////////////
-// API's Specific to Purify //
-//////////////////////////////
-
-// TRUE when Purify is running.
-int __cdecl PurifyIsRunning(void)			;
-//
-// Print a string to the viewer.
-//
-int __cdecl PurePrintf(const char *fmt, ...)		;
-int __cdecl PurifyPrintf(const char *fmt, ...)		;
-//
-// Purify functions for leak and memory-in-use functionalty.
-//
-int __cdecl PurifyNewInuse(void)			;
-int __cdecl PurifyAllInuse(void) 			;
-int __cdecl PurifyClearInuse(void)			;
-int __cdecl PurifyNewLeaks(void)			;
-int __cdecl PurifyAllLeaks(void)			;
-int __cdecl PurifyClearLeaks(void)			;
-//
-// Purify functions for handle leakage.
-//
-int __cdecl PurifyAllHandlesInuse(void)			;
-int __cdecl PurifyNewHandlesInuse(void)			;
-//
-// Functions that tell you about the state of memory.
-//
-int __cdecl PurifyDescribe(void *addr)			;
-int __cdecl PurifyWhatColors(void *addr, int size) 	;
-//
-// Functions to test the state of memory.  If the memory is not
-// accessible, an error is signaled just as if there were a memory
-// reference and the function returns false.
-//
-int __cdecl PurifyAssertIsReadable(const void *addr, int size)	;
-int __cdecl PurifyAssertIsWritable(const void *addr, int size)	;
-//
-// Functions to test the state of memory.  If the memory is not
-// accessible, these functions return false.  No error is signaled.
-//
-int __cdecl PurifyIsReadable(const void *addr, int size)	;
-int __cdecl PurifyIsWritable(const void *addr, int size)	;
-int __cdecl PurifyIsInitialized(const void *addr, int size)	;
-//
-// Functions to set the state of memory.
-//
-void __cdecl PurifyMarkAsInitialized(void *addr, int size)	;
-void __cdecl PurifyMarkAsUninitialized(void *addr, int size)	;
-//
-// Functions to do late detection of ABWs, FMWs, IPWs.
-//
-#define PURIFY_HEAP_CRT 					0xfffffffe
-#define PURIFY_HEAP_ALL 					0xfffffffd
-#define PURIFY_HEAP_BLOCKS_LIVE 			0x80000000
-#define PURIFY_HEAP_BLOCKS_DEFERRED_FREE 	0x40000000
-#define PURIFY_HEAP_BLOCKS_ALL 				(PURIFY_HEAP_BLOCKS_LIVE|PURIFY_HEAP_BLOCKS_DEFERRED_FREE)
-int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr)	;
-int __cdecl PurifySetLateDetectScanCounter(int counter);
-int __cdecl PurifySetLateDetectScanInterval(int seconds);
-
-
-////////////////////////////////
-// API's Specific to Quantify //
-////////////////////////////////
-
-// TRUE when Quantify is running.
-int __cdecl QuantifyIsRunning(void)			;
-
-//
-// Functions for controlling collection
-//
-int __cdecl QuantifyDisableRecordingData(void)		;
-int __cdecl QuantifyStartRecordingData(void)		;
-int __cdecl QuantifyStopRecordingData(void)		;
-int __cdecl QuantifyClearData(void)			;
-int __cdecl QuantifyIsRecordingData(void)		;
-
-// Add a comment to the dataset
-int __cdecl QuantifyAddAnnotation(char *)		;
-
-// Save the current data, creating a "checkpoint" dataset
-int __cdecl QuantifySaveData(void)			;
-
-////////////////////////////////
-// API's Specific to Coverage //
-////////////////////////////////
-
-// TRUE when Coverage is running.
-int __cdecl CoverageIsRunning(void)			;
-//
-// Functions for controlling collection
-//
-int __cdecl CoverageDisableRecordingData(void)		;
-int __cdecl CoverageStartRecordingData(void)		;
-int __cdecl CoverageStopRecordingData(void)		;
-int __cdecl CoverageClearData(void)			;
-int __cdecl CoverageIsRecordingData(void)		;
-// Add a comment to the dataset
-int __cdecl CoverageAddAnnotation(char *)		;
-
-// Save the current data, creating a "checkpoint" dataset
-int __cdecl CoverageSaveData(void)			;
-
-
-
-
-////////////////////////////////
-// API's Specific to Purelock //
-////////////////////////////////
-
-// TRUE when Purelock is running.
-int __cdecl PurelockIsRunning(void)			;
-
-
-
-
-#if defined(c_plusplus) || defined(__cplusplus)
-}
-#endif
deleted file mode 100644
--- a/xpcom/base/pure_api.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Header file of Pure API function declarations.
- *
- * Explicitly no copyright.
- * You may recompile and redistribute these definitions as required.
- *
- * NOTE1: In some situations when compiling with MFC, you should
- *        enable the setting 'Not using precompiled headers' in Visual C++
- *        to avoid a compiler diagnostic.
- *
- * NOTE2: This file works through the use of deep magic.  Calls to functions
- *        in this file are replaced with calls into the OCI runtime system
- *        when an instrumented version of this program is run.
- *
- * NOTE3: The static vars avoidGy_n (where n is a unique number) are used
- *        to prevent optimizing the functions away when compiler option
- *        /Gy is set. This is needed so that NOTE2 works properly.
- */
-static int avoidGy_1;
-static int avoidGy_2;
-static int avoidGy_3;
-static int avoidGy_4;
-static int avoidGy_5;
-static int avoidGy_6;
-static int avoidGy_7;
-static int avoidGy_8;
-static int avoidGy_9;
-static int avoidGy_10;
-static int avoidGy_11;
-static int avoidGy_12;
-static int avoidGy_13;
-static int avoidGy_14;
-static int avoidGy_15;
-static int avoidGy_16;
-static int avoidGy_17;
-static int avoidGy_18;
-static int avoidGy_19;
-static int avoidGy_20;
-static int avoidGy_21;
-static int avoidGy_22;
-static int avoidGy_23;
-static int avoidGy_24;
-static int avoidGy_25;
-static int avoidGy_26;
-static int avoidGy_27;
-static int avoidGy_28;
-static int avoidGy_29;
-static int avoidGy_30;
-static int avoidGy_31;
-static int avoidGy_32;
-static int avoidGy_33;
-static int avoidGy_34;
-static int avoidGy_35;
-static int avoidGy_36;
-static int avoidGy_37;
-static int avoidGy_38;
-static int avoidGy_39;
-static int avoidGy_40;
-static int avoidGy_41;
-static int avoidGy_42;
-static int avoidGy_43;
-static int avoidGy_44;
-static int avoidGy_45;
-static int avoidGy_46;
-static int avoidGy_47;
-static int avoidGy_48;
-static int avoidGy_49;
-static int avoidGy_50;
-static int avoidGy_51;
-static int avoidGy_52;
-static int avoidGy_53;
-static int avoidGy_54;
-static int avoidGy_55;
-static int avoidGy_56;
-static int avoidGy_57;
-static int avoidGy_58;
-static int avoidGy_59;
-static int avoidGy_60;
-static int avoidGy_PL_01;
-__declspec(dllexport) int __cdecl PurePrintf(const char *fmt, ...) { avoidGy_1++; fmt; return 0; }
-__declspec(dllexport) int __cdecl PurifyIsRunning(void) { avoidGy_2++; return 0; }
-__declspec(dllexport) int __cdecl PurifyPrintf(const char *fmt, ...) { avoidGy_3++; fmt; return 0; }
-__declspec(dllexport) int __cdecl PurifyNewInuse(void) { avoidGy_4++; return 0; }
-__declspec(dllexport) int __cdecl PurifyAllInuse(void) { avoidGy_5++; return 0; }
-__declspec(dllexport) int __cdecl PurifyClearInuse(void) { avoidGy_6++; return 0; }
-__declspec(dllexport) int __cdecl PurifyNewLeaks(void) { avoidGy_7++; return 0; }
-__declspec(dllexport) int __cdecl PurifyAllLeaks(void) { avoidGy_8++; return 0; }
-__declspec(dllexport) int __cdecl PurifyClearLeaks(void) { avoidGy_9++; return 0; }
-__declspec(dllexport) int __cdecl PurifyAllHandlesInuse(void) { avoidGy_10++; return 0; }
-__declspec(dllexport) int __cdecl PurifyNewHandlesInuse(void) { avoidGy_11++; return 0; }
-__declspec(dllexport) int __cdecl PurifyDescribe(void *addr) { avoidGy_12++; addr; return 0; }
-__declspec(dllexport) int __cdecl PurifyWhatColors(void *addr, int size) { avoidGy_13++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyAssertIsReadable(const void *addr, int size) { avoidGy_14++; addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyAssertIsWritable(const void *addr, int size) { avoidGy_15++; addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsReadable(const void *addr, int size) { avoidGy_16++; addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsWritable(const void *addr, int size) { avoidGy_17++; addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyIsInitialized(const void *addr, int size) { avoidGy_18++; addr; size; return 1; }
-__declspec(dllexport) int __cdecl PurifyRed(void *addr, int size) { avoidGy_19++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyGreen(void *addr, int size) { avoidGy_20++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyYellow(void *addr, int size) { avoidGy_21++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyBlue(void *addr, int size) { avoidGy_22++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkAsInitialized(void *addr, int size) { avoidGy_23++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkAsUninitialized(void *addr, int size) { avoidGy_24++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkForTrap(void *addr, int size) { avoidGy_25++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyMarkForNoTrap(void *addr, int size) { avoidGy_26++; addr; size; return 0; }
-__declspec(dllexport) int __cdecl PurifyHeapValidate(unsigned int hHeap, unsigned int dwFlags, const void *addr) 
- { avoidGy_27++; hHeap; dwFlags; addr; return 1; }
-__declspec(dllexport) int __cdecl PurifySetLateDetectScanCounter(int counter) { avoidGy_28++; counter; return 0; };
-__declspec(dllexport) int __cdecl PurifySetLateDetectScanInterval(int seconds) { avoidGy_29++; seconds; return 0; };
-__declspec(dllexport) int __cdecl CoverageIsRunning(void) { avoidGy_30++; return 0; }
-__declspec(dllexport) int __cdecl CoverageDisableRecordingData(void) { avoidGy_31++; return 0; }
-__declspec(dllexport) int __cdecl CoverageStartRecordingData(void) { avoidGy_32++; return 0; }
-__declspec(dllexport) int __cdecl CoverageStopRecordingData(void) { avoidGy_33++; return 0; }
-__declspec(dllexport) int __cdecl CoverageClearData(void) { avoidGy_34++; return 0; }
-__declspec(dllexport) int __cdecl CoverageIsRecordingData(void) { avoidGy_35++; return 0; }
-__declspec(dllexport) int __cdecl CoverageAddAnnotation(char *str) { avoidGy_36++; str; return 0; }
-__declspec(dllexport) int __cdecl CoverageSaveData(void) { avoidGy_37++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyIsRunning(void) { avoidGy_42++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyDisableRecordingData(void) { avoidGy_43++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyStartRecordingData(void) { avoidGy_44++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyStopRecordingData(void) { avoidGy_45++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyClearData(void) { avoidGy_46++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyIsRecordingData(void) { avoidGy_47++; return 0; }
-__declspec(dllexport) int __cdecl QuantifyAddAnnotation(char *str) { avoidGy_48++; str; return 0; }
-__declspec(dllexport) int __cdecl QuantifySaveData(void) { avoidGy_49++; return 0; }
-__declspec(dllexport) int __cdecl PurelockIsRunning(void) { avoidGy_PL_01++; return 0; }