Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Thu, 16 Feb 2017 13:20:11 +0100
changeset 343269 ab0a5b797f02b569bce706e7d6c08f99729687f9
parent 343268 fb2b5dae66c753aa27bf1543be813360a6f60769 (current diff)
parent 343249 2737f66ad6ac74a688bde788b319122f2001b92b (diff)
child 343270 4158b1d8bb2ab89048c8be560b35fcfc12726a84
child 343285 9ac4dccad20f643037235f2f03e5e322be07f593
push id31374
push userkwierso@gmail.com
push dateThu, 16 Feb 2017 17:26:30 +0000
treeherdermozilla-central@4158b1d8bb2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland
toolkit/components/sqlite/moz.build
toolkit/components/sqlite/sqlite_internal.js
toolkit/components/sqlite/tests/xpcshell/.eslintrc.js
toolkit/components/sqlite/tests/xpcshell/data/chrome.manifest
toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_internal.js
toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_shared.js
toolkit/components/sqlite/tests/xpcshell/test_sqlite_internal.js
toolkit/components/sqlite/tests/xpcshell/xpcshell.ini
tools/profiler/lul/LulPlatformMacros.h
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -380,22 +380,33 @@ function getTabStateForContentWindow(aCo
 
 function getInnerWindowIDForWindow(aContentWindow) {
   return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                        .getInterface(Ci.nsIDOMWindowUtils)
                        .currentInnerWindowID;
 }
 
 function getMessageManagerForWindow(aContentWindow) {
-  let ir = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIDocShell)
-                         .sameTypeRootTreeItem
-                         .QueryInterface(Ci.nsIInterfaceRequestor);
+  aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor);
+
+  let docShell;
   try {
-    // If e10s is disabled, this throws NS_NOINTERFACE for closed tabs.
+    // This throws NS_NOINTERFACE for closed tabs.
+    docShell = aContentWindow.getInterface(Ci.nsIDocShell);
+  } catch (e) {
+    if (e.result == Cr.NS_NOINTERFACE) {
+      return null;
+    }
+    throw e;
+  }
+
+  let ir = docShell.sameTypeRootTreeItem
+                   .QueryInterface(Ci.nsIInterfaceRequestor);
+  try {
+    // This throws NS_NOINTERFACE for closed tabs (only with e10s enabled).
     return ir.getInterface(Ci.nsIContentFrameMessageManager);
   } catch (e) {
     if (e.result == Cr.NS_NOINTERFACE) {
       return null;
     }
     throw e;
   }
 }
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -43,17 +43,18 @@ bool sAudioChannelMutedByDefault = false
 bool sAudioChannelCompeting = false;
 bool sXPCOMShuttingDown = false;
 
 class NotifyChannelActiveRunnable final : public Runnable
 {
 public:
   NotifyChannelActiveRunnable(uint64_t aWindowID, AudioChannel aAudioChannel,
                               bool aActive)
-    : mWindowID(aWindowID)
+    : Runnable("NotifyChannelActiveRunnable")
+    , mWindowID(aWindowID)
     , mAudioChannel(aAudioChannel)
     , mActive(aActive)
   {}
 
   NS_IMETHOD Run() override
   {
     nsCOMPtr<nsIObserverService> observerService =
       services::GetObserverService();
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -1232,16 +1232,17 @@ FragmentOrElement::FireNodeInserted(nsID
 // nsISupports implementation
 
 #define SUBTREE_UNBINDINGS_PER_RUNNABLE 500
 
 class ContentUnbinder : public Runnable
 {
 public:
   ContentUnbinder()
+    : Runnable("ContentUnbinder")
   {
     mLast = this;
   }
 
   ~ContentUnbinder()
   {
     Run();
   }
--- a/dom/base/nsContentSink.cpp
+++ b/dom/base/nsContentSink.cpp
@@ -60,16 +60,17 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsConten
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
   NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
+  NS_INTERFACE_MAP_ENTRY(nsINamed)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
   if (tmp->mDocument) {
     tmp->mDocument->RemoveObserver(tmp);
@@ -1622,8 +1623,21 @@ nsContentSink::NotifyDocElementCreated(n
       NotifyObservers(domDoc, "document-element-inserted",
                       EmptyString().get());
   }
 
   nsContentUtils::DispatchChromeEvent(aDoc, aDoc,
                                       NS_LITERAL_STRING("DOMDocElementInserted"),
                                       true, false);
 }
+
+NS_IMETHODIMP
+nsContentSink::GetName(nsACString& aName)
+{
+  aName.AssignASCII("nsContentSink_timer");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsContentSink::SetName(const char* aName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
--- a/dom/base/nsContentSink.h
+++ b/dom/base/nsContentSink.h
@@ -71,24 +71,27 @@ extern mozilla::LazyLogModule gContentSi
 //----------------------------------------------------------------------
 
 // 1/2 second fudge factor for window creation
 #define NS_DELAY_FOR_WINDOW_CREATION  500000
 
 class nsContentSink : public nsICSSLoaderObserver,
                       public nsSupportsWeakReference,
                       public nsStubDocumentObserver,
-                      public nsITimerCallback
+                      public nsITimerCallback,
+                      public nsINamed
 {
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsContentSink,
                                            nsICSSLoaderObserver)
     // nsITimerCallback
   NS_DECL_NSITIMERCALLBACK
 
+  NS_DECL_NSINAMED
+
   // nsICSSLoaderObserver
   NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
                               bool aWasAlternate,
                               nsresult aStatus) override;
 
   virtual nsresult ProcessMETATag(nsIContent* aContent);
 
   // nsIContentSink implementation helpers
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3814,17 +3814,17 @@ nsDocument::CreateShell(nsPresContext* a
   RebuildUserFontSet();
 
   return shell.forget();
 }
 
 void
 nsDocument::MaybeRescheduleAnimationFrameNotifications()
 {
-  if (!mPresShell || !IsEventHandlingEnabled()) {
+  if (!mPresShell || !IsEventHandlingEnabled() || AnimationsPaused()) {
     // bail out for now, until one of those conditions changes
     return;
   }
 
   nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver();
   if (!mFrameRequestCallbacks.IsEmpty()) {
     rd->ScheduleFrameRequestCallbacks(this);
   }
@@ -10068,17 +10068,17 @@ nsIDocument::ScheduleFrameRequestCallbac
 }
 
 void
 nsIDocument::CancelFrameRequestCallback(int32_t aHandle)
 {
   // mFrameRequestCallbacks is stored sorted by handle
   if (mFrameRequestCallbacks.RemoveElementSorted(aHandle) &&
       mFrameRequestCallbacks.IsEmpty() &&
-      mPresShell && IsEventHandlingEnabled()) {
+      mPresShell && IsEventHandlingEnabled() && !AnimationsPaused()) {
     mPresShell->GetPresContext()->RefreshDriver()->
       RevokeFrameRequestCallbacks(this);
   }
 }
 
 nsresult
 nsDocument::GetStateObject(nsIVariant** aState)
 {
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -179,17 +179,17 @@ nsAsyncInstantiateEvent::Run()
 
 // Checks to see if the content for a plugin instance should be unloaded
 // (outside an active document) or stopped (in a document but unrendered). This
 // is used to allow scripts to move a plugin around the document hierarchy
 // without re-instantiating it.
 class CheckPluginStopEvent : public Runnable {
 public:
   explicit CheckPluginStopEvent(nsObjectLoadingContent* aContent)
-  : mContent(aContent) {}
+  : Runnable("CheckPluginStopEvent"), mContent(aContent) {}
 
   ~CheckPluginStopEvent() override = default;
 
   NS_IMETHOD Run() override;
 
 private:
   nsCOMPtr<nsIObjectLoadingContent> mContent;
 };
--- a/dom/base/nsWindowMemoryReporter.cpp
+++ b/dom/base/nsWindowMemoryReporter.cpp
@@ -651,18 +651,19 @@ nsWindowMemoryReporter::AsyncCheckForGho
   // prevents the timer from being completely starved if it is repeatedly killed
   // and restarted.
   int32_t timeSinceLastCheck = (TimeStamp::NowLoRes() - mLastCheckForGhostWindows).ToSeconds();
   int32_t timerDelay = (kTimeBetweenChecks - std::min(timeSinceLastCheck, kTimeBetweenChecks)) * PR_MSEC_PER_SEC;
 
   mCheckTimer = do_CreateInstance("@mozilla.org/timer;1");
 
   if (mCheckTimer) {
-    mCheckTimer->InitWithFuncCallback(CheckTimerFired, nullptr,
-                                      timerDelay, nsITimer::TYPE_ONE_SHOT);
+    mCheckTimer->InitWithNamedFuncCallback(CheckTimerFired, nullptr,
+                                           timerDelay, nsITimer::TYPE_ONE_SHOT,
+                                           "nsWindowMemoryReporter::AsyncCheckForGhostWindows_timer");
   }
 }
 
 void
 nsWindowMemoryReporter::ObserveAfterMinimizeMemoryUsage()
 {
   // Someone claims they've done enough GC/CCs so that all eligible windows
   // have been free'd.  So we deem that any windows which satisfy ghost
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -191,28 +191,31 @@ PrintDocTreeAll(nsIDocShellTreeItem* aIt
 #define NS_MODIFIER_ALT      4
 #define NS_MODIFIER_META     8
 #define NS_MODIFIER_OS       16
 
 /******************************************************************/
 /* mozilla::UITimerCallback                                       */
 /******************************************************************/
 
-class UITimerCallback final : public nsITimerCallback
+class UITimerCallback final :
+    public nsITimerCallback,
+    public nsINamed
 {
 public:
   UITimerCallback() : mPreviousCount(0) {}
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
+  NS_DECL_NSINAMED
 private:
   ~UITimerCallback() = default;
   uint32_t mPreviousCount;
 };
 
-NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback)
+NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)
 
 // If aTimer is nullptr, this method always sends "user-interaction-inactive"
 // notification.
 NS_IMETHODIMP
 UITimerCallback::Notify(nsITimer* aTimer)
 {
   nsCOMPtr<nsIObserverService> obs =
     mozilla::services::GetObserverService();
@@ -228,16 +231,29 @@ UITimerCallback::Notify(nsITimer* aTimer
   } else {
     obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
     EventStateManager::UpdateUserActivityTimer();
   }
   mPreviousCount = gMouseOrKeyboardEventCounter;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+UITimerCallback::GetName(nsACString& aName)
+{
+  aName.AssignASCII("UITimerCallback_timer");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+UITimerCallback::SetName(const char* aName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 /******************************************************************/
 /* mozilla::OverOutElementsWrapper                                */
 /******************************************************************/
 
 OverOutElementsWrapper::OverOutElementsWrapper()
   : mLastOverFrame(nullptr)
 {
 }
--- a/dom/events/IMEContentObserver.h
+++ b/dom/events/IMEContentObserver.h
@@ -213,18 +213,20 @@ private:
     {
       eChangeEventType_Focus,
       eChangeEventType_Selection,
       eChangeEventType_Text,
       eChangeEventType_Position,
       eChangeEventType_CompositionEventHandled
     };
 
-    explicit AChangeEvent(IMEContentObserver* aIMEContentObserver)
-      : mIMEContentObserver(aIMEContentObserver)
+    explicit AChangeEvent(const char* aName,
+                          IMEContentObserver* aIMEContentObserver)
+      : Runnable(aName)
+      , mIMEContentObserver(aIMEContentObserver)
     {
       MOZ_ASSERT(mIMEContentObserver);
     }
 
     RefPtr<IMEContentObserver> mIMEContentObserver;
 
     /**
      * CanNotifyIME() checks if mIMEContentObserver can and should notify IME.
@@ -236,17 +238,17 @@ private:
      */
     bool IsSafeToNotifyIME(ChangeEventType aChangeEventType) const;
   };
 
   class IMENotificationSender: public AChangeEvent
   {
   public:
     explicit IMENotificationSender(IMEContentObserver* aIMEContentObserver)
-      : AChangeEvent(aIMEContentObserver)
+      : AChangeEvent("IMENotificationSender", aIMEContentObserver)
       , mIsRunning(false)
     {
     }
     NS_IMETHOD Run() override;
 
   private:
     void SendFocusSet();
     void SendSelectionChange();
--- a/dom/html/nsHTMLDNSPrefetch.cpp
+++ b/dom/html/nsHTMLDNSPrefetch.cpp
@@ -290,17 +290,18 @@ nsHTMLDNSPrefetch::nsDeferrals::Add(uint
     return NS_ERROR_DNS_LOOKUP_QUEUE_FULL;
     
   mEntries[mHead].mFlags = flags;
   mEntries[mHead].mElement = do_GetWeakReference(aElement);
   mHead = (mHead + 1) & sMaxDeferredMask;
 
   if (!mActiveLoaderCount && !mTimerArmed && mTimer) {
     mTimerArmed = true;
-    mTimer->InitWithFuncCallback(Tick, this, 2000, nsITimer::TYPE_ONE_SHOT);
+    mTimer->InitWithNamedFuncCallback(Tick, this, 2000, nsITimer::TYPE_ONE_SHOT,
+                                      "nsHTMLDNSPrefetch::nsDeferrals::Tick");
   }
   
   return NS_OK;
 }
 
 void
 nsHTMLDNSPrefetch::nsDeferrals::SubmitQueue()
 {
--- a/dom/ipc/CrashReporterChild.cpp
+++ b/dom/ipc/CrashReporterChild.cpp
@@ -19,21 +19,16 @@ CrashReporterChild::GetCrashReporter()
 {
   const ManagedContainer<PCrashReporterChild>* reporters = nullptr;
   switch (XRE_GetProcessType()) {
     case GeckoProcessType_Content: {
       ContentChild* child = ContentChild::GetSingleton();
       reporters = &child->ManagedPCrashReporterChild();
       break;
     }
-    case GeckoProcessType_Plugin: {
-      PluginModuleChild* child = PluginModuleChild::GetChrome();
-      reporters = &child->ManagedPCrashReporterChild();
-      break;
-    }
     default:
       break;
   }
   if (!reporters) {
     return nullptr;
   }
   return LoneManagedOrNullAsserts(*reporters);
 }
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -35,44 +35,16 @@ public:
    * GenerateChildData and FinalizeChildData.
    *
    * @returns true if successful, false otherwise.
    */
   template<class Toplevel>
   bool
   GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
 
-  /*
-   * Attempt to generate a parent/child pair of minidumps from the given
-   * toplevel actor. This calls CrashReporter::CreateMinidumpsAndPair to
-   * generate the minidumps. Crash reporter annotations set prior to this
-   * call will be saved via PairedDumpCallbackExtra into an .extra file
-   * under the proper crash id. AnnotateCrashReport annotations are not
-   * set in this call and the report is not finalized.
-   *
-   * @returns true if successful, false otherwise.
-   */
-  template<class Toplevel>
-  bool
-  GeneratePairedMinidump(Toplevel* t);
-
-  /*
-   * Attempts to take a minidump of the current process and pair that with
-   * a named minidump handed in by the caller.
-   *
-   * @param aTopLevel - top level actor this reporter is associated with.
-   * @param aMinidump - the minidump to associate with.
-   * @param aPairName - the name of the additional minidump.
-   * @returns true if successful, false otherwise.
-   */
-  template<class Toplevel>
-  bool
-  GenerateMinidumpAndPair(Toplevel* aTopLevel, nsIFile* aMinidump,
-                          const nsACString& aPairName);
-
   /**
    * Apply child process annotations to an existing paired mindump generated
    * with GeneratePairedMinidump.
    *
    * Be careful about calling generate apis immediately after this call,
    * see FinalizeChildData.
    *
    * @param processNotes (optional) - Additional notes to append. Annotations
@@ -110,25 +82,16 @@ public:
    * Submits a raw minidump handed in, calls GenerateChildData and
    * FinalizeChildData. Used by content plugins and gmp.
    *
    * @returns true if successful, false otherwise.
    */
   bool
   GenerateCrashReportForMinidump(nsIFile* minidump,
                                  const AnnotationTable* processNotes);
-
-  /*
-   * Instantiate a new crash reporter actor from a given parent that manages
-   * the protocol.
-   *
-   * @returns true if successful, false otherwise.
-   */
-  template<class Toplevel>
-  static bool CreateCrashReporter(Toplevel* actor);
 #endif // MOZ_CRASHREPORTER
 
   /*
    * Initialize this reporter with data from the child process.
    */
   void
   SetChildData(const NativeThreadId& id, const uint32_t& processType);
 
@@ -176,69 +139,16 @@ public:
   // stores the child process type
   GeckoProcessType mProcessType;
   bool mInitialized;
 };
 
 #ifdef MOZ_CRASHREPORTER
 template<class Toplevel>
 inline bool
-CrashReporterParent::GeneratePairedMinidump(Toplevel* t)
-{
-  mozilla::ipc::ScopedProcessHandle child;
-#ifdef XP_MACOSX
-  child = t->Process()->GetChildTask();
-#else
-  if (!base::OpenPrivilegedProcessHandle(t->OtherPid(), &child.rwget())) {
-    NS_WARNING("Failed to open child process handle.");
-    return false;
-  }
-#endif
-  nsCOMPtr<nsIFile> childDump;
-  if (CrashReporter::CreateMinidumpsAndPair(child,
-                                            mMainThread,
-                                            NS_LITERAL_CSTRING("browser"),
-                                            nullptr, // pair with a dump of this process and thread
-                                            getter_AddRefs(childDump)) &&
-      CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) {
-    return true;
-  }
-  return false;
-}
-
-template<class Toplevel>
-inline bool
-CrashReporterParent::GenerateMinidumpAndPair(Toplevel* aTopLevel,
-                                             nsIFile* aMinidumpToPair,
-                                             const nsACString& aPairName)
-{
-  mozilla::ipc::ScopedProcessHandle childHandle;
-#ifdef XP_MACOSX
-  childHandle = aTopLevel->Process()->GetChildTask();
-#else
-  if (!base::OpenPrivilegedProcessHandle(aTopLevel->OtherPid(),
-                                         &childHandle.rwget())) {
-    NS_WARNING("Failed to open child process handle.");
-    return false;
-  }
-#endif
-  nsCOMPtr<nsIFile> targetDump;
-  if (CrashReporter::CreateMinidumpsAndPair(childHandle,
-                                            mMainThread, // child thread id
-                                            aPairName,
-                                            aMinidumpToPair,
-                                            getter_AddRefs(targetDump)) &&
-      CrashReporter::GetIDFromMinidump(targetDump, mChildDumpID)) {
-    return true;
-  }
-  return false;
-}
-
-template<class Toplevel>
-inline bool
 CrashReporterParent::GenerateCrashReport(Toplevel* t,
                                          const AnnotationTable* processNotes)
 {
   nsCOMPtr<nsIFile> crashDump;
   if (t->TakeMinidump(getter_AddRefs(crashDump), nullptr) &&
       CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
     bool result = GenerateChildData(processNotes);
     FinalizeChildData();
@@ -274,33 +184,14 @@ CrashReporterParent::GenerateCompleteMin
       CrashReporter::GetIDFromMinidump(childDump, mChildDumpID)) {
     bool result = GenerateChildData(nullptr);
     FinalizeChildData();
     return result;
   }
   return false;
 }
 
-template<class Toplevel>
-/* static */ bool
-CrashReporterParent::CreateCrashReporter(Toplevel* actor)
-{
-#ifdef MOZ_CRASHREPORTER
-  NativeThreadId id;
-  uint32_t processType;
-  PCrashReporterParent* p =
-      actor->CallPCrashReporterConstructor(&id, &processType);
-  if (p) {
-    static_cast<CrashReporterParent*>(p)->SetChildData(id, processType);
-  } else {
-    NS_ERROR("Error creating crash reporter actor");
-  }
-  return !!p;
-#endif
-  return false;
-}
-
 #endif
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CrashReporterParent_h
--- a/dom/ipc/PCrashReporter.ipdl
+++ b/dom/ipc/PCrashReporter.ipdl
@@ -15,17 +15,17 @@ struct Mapping {
   nsCString library_name;
   nsCString file_id;
   uintptr_t start_address;
   size_t mapping_length;
   size_t file_offset;
 };
 
 async protocol PCrashReporter {
-  manager PContent or PPluginModule;
+  manager PContent;
 parent:
   async AnnotateCrashReport(nsCString key, nsCString data);
   async AppendAppNotes(nsCString data);
   async __delete__();
 };
 
 }
 }
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -292,17 +292,18 @@ ContentListener::HandleEvent(nsIDOMEvent
 
 class TabChild::DelayedDeleteRunnable final
   : public Runnable
 {
     RefPtr<TabChild> mTabChild;
 
 public:
     explicit DelayedDeleteRunnable(TabChild* aTabChild)
-      : mTabChild(aTabChild)
+      : Runnable("TabChild::DelayedDeleteRunnable")
+      , mTabChild(aTabChild)
     {
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(aTabChild);
     }
 
 private:
     ~DelayedDeleteRunnable()
     {
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -44,24 +44,25 @@ struct NotificationAndReportStringId
 // small period of time, in order to provide a synthesized analysis.
 //
 // Referenced by the document through a nsINode property, mTimer, and
 // inter-task captures.
 // When notified that the document is dead, or when the timer expires but
 // nothing new happened, StopWatching() will remove the document property and
 // timer (if present), so no more work will happen and the watcher will be
 // destroyed once all references are gone.
-class DecoderDoctorDocumentWatcher : public nsITimerCallback
+class DecoderDoctorDocumentWatcher : public nsITimerCallback, public nsINamed
 {
 public:
   static already_AddRefed<DecoderDoctorDocumentWatcher>
   RetrieveOrCreate(nsIDocument* aDocument);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
+  NS_DECL_NSINAMED
 
   void AddDiagnostics(DecoderDoctorDiagnostics&& aDiagnostics,
                       const char* aCallSite);
 
 private:
   explicit DecoderDoctorDocumentWatcher(nsIDocument* aDocument);
   virtual ~DecoderDoctorDocumentWatcher();
 
@@ -113,17 +114,17 @@ private:
   typedef nsTArray<Diagnostics> DiagnosticsSequence;
   DiagnosticsSequence mDiagnosticsSequence;
 
   nsCOMPtr<nsITimer> mTimer; // Keep timer alive until we run.
   DiagnosticsSequence::size_type mDiagnosticsHandled = 0;
 };
 
 
-NS_IMPL_ISUPPORTS(DecoderDoctorDocumentWatcher, nsITimerCallback)
+NS_IMPL_ISUPPORTS(DecoderDoctorDocumentWatcher, nsITimerCallback, nsINamed)
 
 // static
 already_AddRefed<DecoderDoctorDocumentWatcher>
 DecoderDoctorDocumentWatcher::RetrieveOrCreate(nsIDocument* aDocument)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aDocument);
   RefPtr<DecoderDoctorDocumentWatcher> watcher =
@@ -639,16 +640,28 @@ DecoderDoctorDocumentWatcher::Notify(nsI
     // If more diagnostics come in, we'll treat them as another burst, separately.
     // 'true' to remove the property from the document.
     StopWatching(true);
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DecoderDoctorDocumentWatcher::GetName(nsACString& aName)
+{
+  aName.AssignASCII("DecoderDoctorDocumentWatcher_timer");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DecoderDoctorDocumentWatcher::SetName(const char* aName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
 
 void
 DecoderDoctorDiagnostics::StoreFormatDiagnostics(nsIDocument* aDocument,
                                                  const nsAString& aFormat,
                                                  bool aCanPlay,
                                                  const char* aCallSite)
 {
   MOZ_ASSERT(NS_IsMainThread());
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -859,17 +859,18 @@ ChannelMediaResource::CacheClientNotifyD
   NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
   // NOTE: this can be called with the media cache lock held, so don't
   // block or do anything which might try to acquire a lock!
 
   if (mDataReceivedEvent.IsPending())
     return;
 
   mDataReceivedEvent =
-    NewNonOwningRunnableMethod(this, &ChannelMediaResource::DoNotifyDataReceived);
+    NewNonOwningRunnableMethod("ChannelMediaResource::DoNotifyDataReceived",
+                               this, &ChannelMediaResource::DoNotifyDataReceived);
   NS_DispatchToMainThread(mDataReceivedEvent.get());
 }
 
 void
 ChannelMediaResource::CacheClientNotifyDataEnded(nsresult aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
   mCallback->NotifyDataEnded(aStatus);
--- a/dom/media/MediaStreamGraph.cpp
+++ b/dom/media/MediaStreamGraph.cpp
@@ -1621,17 +1621,18 @@ public:
 private:
   RefPtr<MediaStreamGraphImpl> mGraph;
 };
 
 class MediaStreamGraphStableStateRunnable : public Runnable {
 public:
   explicit MediaStreamGraphStableStateRunnable(MediaStreamGraphImpl* aGraph,
                                                bool aSourceIsMSG)
-    : mGraph(aGraph)
+    : Runnable("MediaStreamGraphStableStateRunnable")
+    , mGraph(aGraph)
     , mSourceIsMSG(aSourceIsMSG)
   {
   }
   NS_IMETHOD Run() override
   {
     if (mGraph) {
       mGraph->RunInStableState(mSourceIsMSG);
     }
--- a/dom/media/gmp/GMPParent.cpp
+++ b/dom/media/gmp/GMPParent.cpp
@@ -451,39 +451,38 @@ GMPParent::EnsureProcessLoaded()
 
   nsresult rv = LoadProcess();
 
   return NS_SUCCEEDED(rv);
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
-GMPParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
+GMPParent::WriteExtraDataForMinidump()
 {
-  notes.Put(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1"));
-  notes.Put(NS_LITERAL_CSTRING("PluginFilename"),
-                               NS_ConvertUTF16toUTF8(mName));
-  notes.Put(NS_LITERAL_CSTRING("PluginName"), mDisplayName);
-  notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mVersion);
+  mCrashReporter->AddNote(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1"));
+  mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), NS_ConvertUTF16toUTF8(mName));
+  mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mDisplayName);
+  mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mVersion);
 }
 
 bool
 GMPParent::GetCrashID(nsString& aResult)
 {
   if (!mCrashReporter) {
     return false;
   }
 
-  AnnotationTable notes(4);
-  WriteExtraDataForMinidump(notes);
+  WriteExtraDataForMinidump();
+  if (!mCrashReporter->GenerateCrashReport(OtherPid())) {
+    return false;
+  }
 
-  return mCrashReporter->GenerateCrashReport(
-    OtherPid(),
-    &notes,
-    &aResult);
+  aResult = mCrashReporter->MinidumpID();
+  return true;
 }
 
 static void
 GMPNotifyObservers(const uint32_t aPluginID, const nsACString& aPluginName, const nsAString& aPluginDumpID)
 {
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   nsCOMPtr<nsIWritablePropertyBag2> propbag =
     do_CreateInstance("@mozilla.org/hash-property-bag;1");
@@ -536,22 +535,23 @@ GMPParent::ActorDestroy(ActorDestroyReas
     MOZ_ASSERT(mState == GMPStateClosing);
     DeleteProcess();
     // Note: final destruction will be Dispatched to ourself
     mService->ReAddOnGMPThread(self);
   }
 }
 
 mozilla::ipc::IPCResult
-GMPParent::RecvInitCrashReporter(Shmem&& aShmem)
+GMPParent::RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId)
 {
 #ifdef MOZ_CRASHREPORTER
   mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
     GeckoProcessType_GMPlugin,
-    aShmem);
+    aShmem,
+    aThreadId);
 #endif
   return IPC_OK();
 }
 
 PGMPStorageParent*
 GMPParent::AllocPGMPStorageParent()
 {
   GMPStorageParent* p = new GMPStorageParent(mNodeId, this);
--- a/dom/media/gmp/GMPParent.h
+++ b/dom/media/gmp/GMPParent.h
@@ -156,22 +156,22 @@ private:
 
   RefPtr<GeckoMediaPluginServiceParent> mService;
   bool EnsureProcessLoaded();
   RefPtr<GenericPromise> ReadGMPMetaData();
   RefPtr<GenericPromise> ReadGMPInfoFile(nsIFile* aFile);
   RefPtr<GenericPromise> ParseChromiumManifest(const nsAString& aJSON); // Main thread.
   RefPtr<GenericPromise> ReadChromiumManifestFile(nsIFile* aFile); // GMP thread.
 #ifdef MOZ_CRASHREPORTER
-  void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
+  void WriteExtraDataForMinidump();
   bool GetCrashID(nsString& aResult);
 #endif
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
-  mozilla::ipc::IPCResult RecvInitCrashReporter(Shmem&& shmem) override;
+  mozilla::ipc::IPCResult RecvInitCrashReporter(Shmem&& shmem, const NativeThreadId& aThreadId) override;
 
   mozilla::ipc::IPCResult RecvPGMPStorageConstructor(PGMPStorageParent* actor) override;
   PGMPStorageParent* AllocPGMPStorageParent() override;
   bool DeallocPGMPStorageParent(PGMPStorageParent* aActor) override;
 
   mozilla::ipc::IPCResult RecvPGMPTimerConstructor(PGMPTimerParent* actor) override;
   PGMPTimerParent* AllocPGMPTimerParent() override;
   bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) override;
--- a/dom/media/gmp/PGMP.ipdl
+++ b/dom/media/gmp/PGMP.ipdl
@@ -13,17 +13,17 @@ namespace mozilla {
 namespace gmp {
 
 intr protocol PGMP
 {
   manages PGMPTimer;
   manages PGMPStorage;
 
 parent:
-  async InitCrashReporter(Shmem shmem);
+  async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
   async PGMPTimer();
   async PGMPStorage();
 
   async PGMPContentChildDestroyed();
 
 child:
   async CrashPluginNow();
   intr StartPlugin(nsString adapter);
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -205,18 +205,16 @@ static void CheckClassInitialized()
   if (!sPluginThreadAsyncCallLock)
     sPluginThreadAsyncCallLock = new Mutex("nsNPAPIPlugin.sPluginThreadAsyncCallLock");
 
   initialized = true;
 
   NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,("NPN callbacks initialized\n"));
 }
 
-NS_IMPL_ISUPPORTS0(nsNPAPIPlugin)
-
 nsNPAPIPlugin::nsNPAPIPlugin()
 {
   memset((void*)&mPluginFuncs, 0, sizeof(mPluginFuncs));
   mPluginFuncs.size = sizeof(mPluginFuncs);
   mPluginFuncs.version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
 
   mLibrary = nullptr;
 }
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -7,37 +7,40 @@
 #define nsNPAPIPlugin_h_
 
 #include "prlink.h"
 #include "npfunctions.h"
 #include "nsPluginHost.h"
 
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/PluginLibrary.h"
+#include "mozilla/RefCounted.h"
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
 
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) ();
 
-class nsNPAPIPlugin : public nsISupports
+// nsNPAPIPlugin is held alive both by active nsPluginTag instances and
+// by active nsNPAPIPluginInstance.
+class nsNPAPIPlugin final
 {
 private:
   typedef mozilla::PluginLibrary PluginLibrary;
 
 public:
   nsNPAPIPlugin();
 
-  NS_DECL_ISUPPORTS
+  NS_INLINE_DECL_REFCOUNTING(nsNPAPIPlugin)
 
   // Constructs and initializes an nsNPAPIPlugin object. A nullptr file path
   // will prevent this from calling NP_Initialize.
   static nsresult CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult);
 
   PluginLibrary* GetLibrary();
   // PluginFuncs() can't fail but results are only valid if GetLibrary() succeeds
   NPPluginFuncs* PluginFuncs();
@@ -54,18 +57,18 @@ public:
                      const nsAString& browserDumpID);
 
   static bool RunPluginOOP(const nsPluginTag *aPluginTag);
 
   nsresult Shutdown();
 
   static nsresult RetainStream(NPStream *pstream, nsISupports **aRetainedPeer);
 
-protected:
-  virtual ~nsNPAPIPlugin();
+private:
+  ~nsNPAPIPlugin();
 
   NPPluginFuncs mPluginFuncs;
   PluginLibrary* mLibrary;
 };
 
 namespace mozilla {
 namespace plugins {
 namespace parent {
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -25,16 +25,17 @@
 #include "AndroidBridge.h"
 #include <map>
 class PluginEventRunnable;
 #endif
 
 #include "mozilla/EventForwards.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/PluginLibrary.h"
+#include "mozilla/RefPtr.h"
 #include "mozilla/WeakPtr.h"
 
 class nsPluginStreamListenerPeer; // browser-initiated stream class
 class nsNPAPIPluginStreamListener; // plugin-initiated stream class
 class nsIPluginInstanceOwner;
 class nsIOutputStream;
 class nsPluginInstanceOwner;
 
@@ -379,17 +380,17 @@ protected:
 
 public:
   // True while creating the plugin, or calling NPP_SetWindow() on it.
   bool mInPluginInitCall;
 
   nsXPIDLCString mFakeURL;
 
 private:
-  nsNPAPIPlugin* mPlugin;
+  RefPtr<nsNPAPIPlugin> mPlugin;
 
   nsTArray<nsNPAPIPluginStreamListener*> mStreamListeners;
 
   nsTArray<nsPluginStreamListenerPeer*> mFileCachedStreamListeners;
 
   nsTArray<PopupControlState> mPopupStates;
 
   char* mMIMEType;
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 protocol PPluginInstance;
 include protocol PPluginScriptableObject;
-include protocol PCrashReporter;
 include protocol PContent;
 include ProfilerTypes;
 
 using NPError from "npapi.h";
 using NPNVariable from "npapi.h";
 using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using class mac_plugin_interposing::NSCursorInfo from "mozilla/plugins/PluginMessageUtils.h";
 using struct nsID from "nsID.h";
@@ -32,17 +31,16 @@ struct PluginSettings
   // These settings come from elsewhere.
   nsCString userAgent;
   bool nativeCursorsSupported;
 };
 
 intr protocol PPluginModule
 {
   manages PPluginInstance;
-  manages PCrashReporter;
 
 both:
   // Window-specific message which instructs the interrupt mechanism to enter
   // a nested event loop for the current interrupt call.
   async ProcessNativeEventsInInterruptCall();
 
 child:
   async DisableFlashProtectedMode();
@@ -87,18 +85,18 @@ child:
 
   // Windows specific message to set up an audio session in the plugin process
   async SetAudioSessionData(nsID aID,
                             nsString aDisplayName,
                             nsString aIconPath);
 
   async SetParentHangTimeout(uint32_t seconds);
 
-  intr PCrashReporter()
-    returns (NativeThreadId tid, uint32_t processType);
+  intr InitCrashReporter(Shmem shmem)
+    returns (NativeThreadId tid);
 
   /**
    * Control the Gecko Profiler in the plugin process.
    */
   async StartProfiler(ProfilerInitParams params);
   async StopProfiler();
 
   async GatherProfile();
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -45,24 +45,26 @@
 #include <shlobj.h>
 #endif
 
 #ifdef MOZ_WIDGET_COCOA
 #include "PluginInterposeOSX.h"
 #include "PluginUtilsOSX.h"
 #endif
 
+#ifdef MOZ_CRASHREPORTER
+#include "mozilla/ipc/CrashReporterClient.h"
+#endif
+
 #include "GeckoProfiler.h"
 
 using namespace mozilla;
 using namespace mozilla::ipc;
 using namespace mozilla::plugins;
 using namespace mozilla::widget;
-using mozilla::dom::CrashReporterChild;
-using mozilla::dom::PCrashReporterChild;
 
 #if defined(XP_WIN)
 const wchar_t * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
 const wchar_t * kMozillaWindowClass = L"MozillaWindowClass";
 #endif
 
 namespace {
 // see PluginModuleChild::GetChrome()
@@ -715,39 +717,23 @@ mozilla::ipc::IPCResult
 PluginModuleChild::RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& aEndpoint)
 {
     if (!CreateForContentProcess(Move(aEndpoint))) {
         return IPC_FAIL(this, "CreateForContentProcess failed");
     }
     return IPC_OK();
 }
 
-PCrashReporterChild*
-PluginModuleChild::AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id,
-                                            uint32_t* processType)
-{
-    return new CrashReporterChild();
-}
-
-bool
-PluginModuleChild::DeallocPCrashReporterChild(PCrashReporterChild* actor)
-{
-    delete actor;
-    return true;
-}
 
 mozilla::ipc::IPCResult
-PluginModuleChild::AnswerPCrashReporterConstructor(
-        PCrashReporterChild* actor,
-        mozilla::dom::NativeThreadId* id,
-        uint32_t* processType)
+PluginModuleChild::AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aOutId)
 {
 #ifdef MOZ_CRASHREPORTER
-    *id = CrashReporter::CurrentThreadId();
-    *processType = XRE_GetProcessType();
+    CrashReporterClient::InitSingletonWithShmem(aShmem);
+    *aOutId = CrashReporter::CurrentThreadId();
 #endif
     return IPC_OK();
 }
 
 void
 PluginModuleChild::ActorDestroy(ActorDestroyReason why)
 {
     if (!mIsChrome) {
@@ -770,16 +756,19 @@ PluginModuleChild::ActorDestroy(ActorDes
 
     if (!mHasShutdown) {
         MOZ_ASSERT(gChromeInstance == this);
         NP_Shutdown();
     }
 
     // doesn't matter why we're being destroyed; it's up to us to
     // initiate (clean) shutdown
+#ifdef MOZ_CRASHREPORTER
+    CrashReporterClient::DestroySingleton();
+#endif
     XRE_ShutdownChildProcess();
 }
 
 void
 PluginModuleChild::CleanUp()
 {
 }
 
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -41,27 +41,22 @@
 #endif
 
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
 
 namespace mozilla {
-namespace dom {
-class PCrashReporterChild;
-} // namespace dom
-
 namespace plugins {
 
 class PluginInstanceChild;
 
 class PluginModuleChild : public PPluginModuleChild
 {
-    typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
 protected:
     virtual mozilla::ipc::RacyInterruptPolicy
     MediateInterruptRace(const MessageInfo& parent,
                          const MessageInfo& child) override
     {
         return MediateRace(parent, child);
     }
 
@@ -118,25 +113,18 @@ protected:
     virtual mozilla::ipc::IPCResult
     RecvSetAudioSessionData(const nsID& aId,
                             const nsString& aDisplayName,
                             const nsString& aIconPath) override;
 
     virtual mozilla::ipc::IPCResult
     RecvSetParentHangTimeout(const uint32_t& aSeconds) override;
 
-    virtual PCrashReporterChild*
-    AllocPCrashReporterChild(mozilla::dom::NativeThreadId* id,
-                             uint32_t* processType) override;
-    virtual bool
-    DeallocPCrashReporterChild(PCrashReporterChild* actor) override;
     virtual mozilla::ipc::IPCResult
-    AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
-                                    mozilla::dom::NativeThreadId* id,
-                                    uint32_t* processType) override;
+    AnswerInitCrashReporter(Shmem&& aShmem, mozilla::dom::NativeThreadId* aId) override;
 
     virtual void
     ActorDestroy(ActorDestroyReason why) override;
 
     virtual mozilla::ipc::IPCResult
     RecvProcessNativeEventsInInterruptCall() override;
 
     virtual mozilla::ipc::IPCResult RecvStartProfiler(const ProfilerInitParams& params) override;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/plugins/PluginModuleParent.h"
 
 #include "base/process_util.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentChild.h"
-#include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/MessageChannel.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
 #include "mozilla/plugins/PluginAsyncSurrogate.h"
 #include "mozilla/plugins/PluginBridge.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/Preferences.h"
@@ -62,25 +61,24 @@
 using base::KillProcess;
 
 using mozilla::PluginLibrary;
 #ifdef MOZ_GECKO_PROFILER
 using mozilla::ProfileGatherer;
 #endif
 using mozilla::ipc::MessageChannel;
 using mozilla::ipc::GeckoChildProcessHost;
-using mozilla::dom::PCrashReporterParent;
-using mozilla::dom::CrashReporterParent;
 
 using namespace mozilla;
 using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
 
 #ifdef MOZ_CRASHREPORTER
-#include "mozilla/dom/CrashReporterParent.h"
+#include "mozilla/ipc/CrashReporterClient.h"
+#include "mozilla/ipc/CrashReporterHost.h"
 
 using namespace CrashReporter;
 #endif
 
 static const char kContentTimeoutPref[] = "dom.ipc.plugins.contentTimeoutSecs";
 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
@@ -593,35 +591,22 @@ PluginModuleChromeParent::OnProcessLaunc
     Preferences::RegisterCallback(TimeoutChanged, kHangUITimeoutPref, this);
     Preferences::RegisterCallback(TimeoutChanged, kHangUIMinDisplayPref, this);
 #endif
 
     RegisterSettingsCallbacks();
 
 #ifdef MOZ_CRASHREPORTER
     // If this fails, we're having IPC troubles, and we're doomed anyways.
-    if (!CrashReporterParent::CreateCrashReporter(this)) {
+    if (!InitCrashReporter()) {
         mShutdown = true;
         Close();
         OnInitFailure();
         return;
     }
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (crashReporter) {
-        crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
-                                           mIsStartingAsync ?
-                                               NS_LITERAL_CSTRING("1") :
-                                               NS_LITERAL_CSTRING("0"));
-    }
-#ifdef XP_WIN
-    { // Scope for lock
-        mozilla::MutexAutoLock lock(mCrashReporterMutex);
-        mCrashReporter = CrashReporter();
-    }
-#endif
 #endif
 
 #if defined(XP_WIN) && defined(_X86_)
     // Protected mode only applies to Windows and only to x86.
     if (!mIsBlocklisted && mIsFlashPlugin &&
         (Preferences::GetBool("dom.ipc.plugins.flash.disable-protected-mode", false) ||
          mSandboxLevel >= 2)) {
         SendDisableFlashProtectedMode();
@@ -681,16 +666,47 @@ PluginModuleChromeParent::WaitForIPCConn
     MOZ_ASSERT(process);
     process->SetCallRunnableImmediately(true);
     if (!process->WaitUntilConnected()) {
         return false;
     }
     return true;
 }
 
+bool
+PluginModuleChromeParent::InitCrashReporter()
+{
+#ifdef MOZ_CRASHREPORTER
+    ipc::Shmem shmem;
+    if (!ipc::CrashReporterClient::AllocShmem(this, &shmem)) {
+        return false;
+    }
+
+    NativeThreadId threadId;
+    if (!CallInitCrashReporter(shmem, &threadId)) {
+        return false;
+    }
+
+    {
+      mozilla::MutexAutoLock lock(mCrashReporterMutex);
+      mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
+        GeckoProcessType_Plugin,
+        shmem,
+        threadId);
+
+      mCrashReporter->AddNote(NS_LITERAL_CSTRING("AsyncPluginInit"),
+                              mIsStartingAsync ?
+                                  NS_LITERAL_CSTRING("1") :
+                                  NS_LITERAL_CSTRING("0"));
+    }
+#endif
+
+    return true;
+}
+
 PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit)
     : mQuirks(QUIRKS_NOT_INITIALIZED)
     , mIsChrome(aIsChrome)
     , mShutdown(false)
     , mHadLocalInstance(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
@@ -698,16 +714,19 @@ PluginModuleParent::PluginModuleParent(b
     , mPlugin(nullptr)
     , mTaskFactory(this)
     , mSandboxLevel(0)
     , mIsFlashPlugin(false)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
     , mIsNPShutdownPending(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
+#ifdef MOZ_CRASHREPORTER
+    , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
+#endif
 {
 #if defined(MOZ_CRASHREPORTER)
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"),
                                        mIsStartingAsync ?
                                            NS_LITERAL_CSTRING("1") :
                                            NS_LITERAL_CSTRING("0"));
 #endif
 }
@@ -747,20 +766,16 @@ PluginModuleChromeParent::PluginModuleCh
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
-#ifdef MOZ_CRASHREPORTER
-    , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
-    , mCrashReporter(nullptr)
-#endif
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
     , mFlashProcess2(0)
     , mFinishInitTask(nullptr)
 #endif
     , mInitOnAsyncConnect(false)
     , mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
@@ -833,52 +848,50 @@ PluginModuleChromeParent::~PluginModuleC
     }
 #endif
 
     mozilla::HangMonitor::UnregisterAnnotator(*this);
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
-PluginModuleChromeParent::WriteExtraDataForMinidump(AnnotationTable& notes)
+PluginModuleChromeParent::WriteExtraDataForMinidump()
 {
-#ifdef XP_WIN
     // mCrashReporterMutex is already held by the caller
     mCrashReporterMutex.AssertCurrentThreadOwns();
-#endif
+
     typedef nsDependentCString CS;
 
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
     else
         filePos++;
-    notes.Put(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
-
-    notes.Put(NS_LITERAL_CSTRING("PluginName"), mPluginName);
-    notes.Put(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion);
-
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (crashReporter) {
+    mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
+
+    mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mPluginName);
+    mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion);
+
+    if (mCrashReporter) {
 #ifdef XP_WIN
         if (mPluginCpuUsageOnHang.Length() > 0) {
-            notes.Put(NS_LITERAL_CSTRING("NumberOfProcessors"),
-                      nsPrintfCString("%d", PR_GetNumberOfProcessors()));
+            mCrashReporter->AddNote(NS_LITERAL_CSTRING("NumberOfProcessors"),
+                                    nsPrintfCString("%d", PR_GetNumberOfProcessors()));
 
             nsCString cpuUsageStr;
             cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100);
-            notes.Put(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
+            mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr);
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
             for (uint32_t i=1; i<mPluginCpuUsageOnHang.Length(); ++i) {
                 nsCString tempStr;
                 tempStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[i] * 100) / 100);
-                notes.Put(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
+                mCrashReporter->AddNote(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr);
             }
 #endif
         }
 #endif
     }
 }
 #endif  // MOZ_CRASHREPORTER
 
@@ -1198,22 +1211,19 @@ PluginModuleContentParent::OnExitedSyncS
 }
 
 void
 PluginModuleChromeParent::TakeFullMinidump(base::ProcessId aContentPid,
                                            const nsAString& aBrowserDumpId,
                                            nsString& aDumpId)
 {
 #ifdef MOZ_CRASHREPORTER
-#ifdef XP_WIN
     mozilla::MutexAutoLock lock(mCrashReporterMutex);
-#endif // XP_WIN
-
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (!crashReporter) {
+
+    if (!mCrashReporter) {
         return;
     }
 
     bool reportsReady = false;
 
     // Check to see if we already have a browser dump id - with e10s plugin
     // hangs we take this earlier (see ProcessHangMonitor) from a background
     // thread. We do this before we message the main thread about the hang
@@ -1222,43 +1232,46 @@ PluginModuleChromeParent::TakeFullMinidu
     nsCOMPtr<nsIFile> browserDumpFile;
     if (!aBrowserDumpId.IsEmpty() &&
         CrashReporter::GetMinidumpForID(aBrowserDumpId, getter_AddRefs(browserDumpFile)) &&
         browserDumpFile &&
         NS_SUCCEEDED(browserDumpFile->Exists(&exists)) && exists)
     {
         // We have a single browser report, generate a new plugin process parent
         // report and pair it up with the browser report handed in.
-        reportsReady = crashReporter->GenerateMinidumpAndPair(this, browserDumpFile,
-                                                              NS_LITERAL_CSTRING("browser"));
+        reportsReady = mCrashReporter->GenerateMinidumpAndPair(
+          this,
+          browserDumpFile,
+          NS_LITERAL_CSTRING("browser"));
+
         if (!reportsReady) {
           browserDumpFile = nullptr;
           CrashReporter::DeleteMinidumpFilesForID(aBrowserDumpId);
         }
     }
 
     // Generate crash report including plugin and browser process minidumps.
     // The plugin process is the parent report with additional dumps including
     // the browser process, content process when running under e10s, and
     // various flash subprocesses if we're the flash module.
     if (!reportsReady) {
-        reportsReady = crashReporter->GeneratePairedMinidump(this);
+        reportsReady = mCrashReporter->GenerateMinidumpAndPair(
+          this,
+          nullptr, // Pair with a dump of this process and thread.
+          NS_LITERAL_CSTRING("browser"));
     }
 
     if (reportsReady) {
-        // Important to set this here, it tells the ActorDestroy handler
-        // that we have an existing crash report that needs to be finalized.
-        mPluginDumpID = crashReporter->ChildDumpID();
-        aDumpId = mPluginDumpID;
+        aDumpId = mCrashReporter->MinidumpID();
         PLUGIN_LOG_DEBUG(
                 ("generated paired browser/plugin minidumps: %s)",
-                 NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
+                 NS_ConvertUTF16toUTF8(aDumpId).get()));
         nsAutoCString additionalDumps("browser");
         nsCOMPtr<nsIFile> pluginDumpFile;
-        if (GetMinidumpForID(mPluginDumpID, getter_AddRefs(pluginDumpFile)) &&
+        if (GetMinidumpForID(aDumpId, getter_AddRefs(pluginDumpFile)) &&
             pluginDumpFile) {
 #ifdef MOZ_CRASHREPORTER_INJECTOR
             // If we have handles to the flash sandbox processes on Windows,
             // include those minidumps as well.
             if (CreatePluginMinidump(mFlashProcess1, 0, pluginDumpFile,
                                      NS_LITERAL_CSTRING("flash1"))) {
                 additionalDumps.AppendLiteral(",flash1");
             }
@@ -1271,17 +1284,17 @@ PluginModuleChromeParent::TakeFullMinidu
                 // Include the content process minidump
                 if (CreatePluginMinidump(aContentPid, 0,
                                          pluginDumpFile,
                                          NS_LITERAL_CSTRING("content"))) {
                     additionalDumps.AppendLiteral(",content");
                 }
             }
         }
-        crashReporter->AnnotateCrashReport(
+        mCrashReporter->AddNote(
             NS_LITERAL_CSTRING("additional_minidumps"),
             additionalDumps);
     } else {
         NS_WARNING("failed to capture paired minidumps from hang");
     }
 #endif // MOZ_CRASHREPORTER
 }
 
@@ -1289,43 +1302,38 @@ void
 PluginModuleChromeParent::TerminateChildProcess(MessageLoop* aMsgLoop,
                                                 base::ProcessId aContentPid,
                                                 const nsCString& aMonitorDescription,
                                                 const nsAString& aDumpId)
 {
 #ifdef MOZ_CRASHREPORTER
     // Start by taking a full minidump if necessary, this is done early
     // because it also needs to lock the mCrashReporterMutex and Mutex doesn't
-    // support recrusive locking.
+    // support recursive locking.
     nsAutoString dumpId;
     if (aDumpId.IsEmpty()) {
         TakeFullMinidump(aContentPid, EmptyString(), dumpId);
     }
 
-#ifdef XP_WIN
     mozilla::MutexAutoLock lock(mCrashReporterMutex);
-    CrashReporterParent* crashReporter = mCrashReporter;
-    if (!crashReporter) {
+    if (!mCrashReporter) {
         // If mCrashReporter is null then the hang has ended, the plugin module
         // is shutting down. There's nothing to do here.
         return;
     }
-#else
-    CrashReporterParent* crashReporter = CrashReporter();
-#endif // XP_WIN
-    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("PluginHang"),
-                                       NS_LITERAL_CSTRING("1"));
-    crashReporter->AnnotateCrashReport(NS_LITERAL_CSTRING("HangMonitorDescription"),
-                                       aMonitorDescription);
+    mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginHang"),
+                            NS_LITERAL_CSTRING("1"));
+    mCrashReporter->AddNote(NS_LITERAL_CSTRING("HangMonitorDescription"),
+                            aMonitorDescription);
 #ifdef XP_WIN
     if (mHangUIParent) {
         unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs();
         if (hangUIDuration) {
             nsPrintfCString strHangUIDuration("%u", hangUIDuration);
-            crashReporter->AnnotateCrashReport(
+            mCrashReporter->AddNote(
                     NS_LITERAL_CSTRING("PluginHangUIDuration"),
                     strHangUIDuration);
         }
     }
 #endif // XP_WIN
 #endif // MOZ_CRASHREPORTER
 
     mozilla::ipc::ScopedProcessHandle geckoChildProcess;
@@ -1496,22 +1504,16 @@ PluginModuleChromeParent::FinishHangUI()
 void
 PluginModuleChromeParent::OnHangUIContinue()
 {
     mHangAnnotationFlags |= kHangUIContinued;
 }
 #endif // XP_WIN
 
 #ifdef MOZ_CRASHREPORTER
-CrashReporterParent*
-PluginModuleChromeParent::CrashReporter()
-{
-    return static_cast<CrashReporterParent*>(LoneManagedOrNullAsserts(ManagedPCrashReporterParent()));
-}
-
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 static void
 RemoveMinidump(nsIFile* minidump)
 {
     if (!minidump)
         return;
 
     minidump->Remove(false);
@@ -1521,65 +1523,64 @@ RemoveMinidump(nsIFile* minidump)
         extraFile->Remove(true);
     }
 }
 #endif // MOZ_CRASHREPORTER_INJECTOR
 
 void
 PluginModuleChromeParent::ProcessFirstMinidump()
 {
-#ifdef XP_WIN
     mozilla::MutexAutoLock lock(mCrashReporterMutex);
-#endif
-    CrashReporterParent* crashReporter = CrashReporter();
-    if (!crashReporter)
+
+    if (!mCrashReporter)
         return;
 
-    AnnotationTable notes(4);
-    WriteExtraDataForMinidump(notes);
-
-    if (!mPluginDumpID.IsEmpty()) {
-        // mPluginDumpID may be set in TerminateChildProcess, which means the
+    WriteExtraDataForMinidump();
+
+    if (mCrashReporter->HasMinidump()) {
+        // A minidump may be set in TerminateChildProcess, which means the
         // process hang monitor has already collected a 3-way browser, plugin,
         // content crash report. If so, update the existing report with our
         // annotations and finalize it. If not, fall through for standard
         // plugin crash report handling.
-        crashReporter->GenerateChildData(&notes);
-        crashReporter->FinalizeChildData();
+        mCrashReporter->FinalizeCrashReport();
         return;
     }
 
     uint32_t sequence = UINT32_MAX;
-    nsCOMPtr<nsIFile> dumpFile;
     nsAutoCString flashProcessType;
-    TakeMinidump(getter_AddRefs(dumpFile), &sequence);
+    RefPtr<nsIFile> dumpFile = mCrashReporter->TakeCrashedChildMinidump(OtherPid(), &sequence);
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     nsCOMPtr<nsIFile> childDumpFile;
     uint32_t childSequence;
 
     if (mFlashProcess1 &&
         TakeMinidumpForChild(mFlashProcess1,
                              getter_AddRefs(childDumpFile),
                              &childSequence)) {
-        if (childSequence < sequence) {
+        if (childSequence < sequence &&
+            mCrashReporter->AdoptMinidump(childDumpFile))
+        {
             RemoveMinidump(dumpFile);
             dumpFile = childDumpFile;
             sequence = childSequence;
             flashProcessType.AssignLiteral("Broker");
         }
         else {
             RemoveMinidump(childDumpFile);
         }
     }
     if (mFlashProcess2 &&
         TakeMinidumpForChild(mFlashProcess2,
                              getter_AddRefs(childDumpFile),
                              &childSequence)) {
-        if (childSequence < sequence) {
+        if (childSequence < sequence &&
+            mCrashReporter->AdoptMinidump(childDumpFile))
+        {
             RemoveMinidump(dumpFile);
             dumpFile = childDumpFile;
             sequence = childSequence;
             flashProcessType.AssignLiteral("Sandbox");
         }
         else {
             RemoveMinidump(childDumpFile);
         }
@@ -1587,23 +1588,22 @@ PluginModuleChromeParent::ProcessFirstMi
 #endif
 
     if (!dumpFile) {
         NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
         return;
     }
 
     PLUGIN_LOG_DEBUG(("got child minidump: %s",
-                      NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
-
-    GetIDFromMinidump(dumpFile, mPluginDumpID);
+                      NS_ConvertUTF16toUTF8(mCrashReporter->MinidumpID()).get()));
+
     if (!flashProcessType.IsEmpty()) {
-        notes.Put(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
+        mCrashReporter->AddNote(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType);
     }
-    crashReporter->GenerateCrashReportForMinidump(dumpFile, &notes);
+    mCrashReporter->FinalizeCrashReport();
 }
 #endif
 
 void
 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
 {
     switch (why) {
     case AbnormalShutdown: {
@@ -1667,18 +1667,28 @@ PluginModuleParent::NotifyPluginCrashed(
     if (!OkToCleanup()) {
         // there's still plugin code on the C++ stack.  try again
         MessageLoop::current()->PostDelayedTask(
             mTaskFactory.NewRunnableMethod(
                 &PluginModuleParent::NotifyPluginCrashed), 10);
         return;
     }
 
-    if (mPlugin)
-        mPlugin->PluginCrashed(mPluginDumpID, mBrowserDumpID);
+    if (!mPlugin) {
+        return;
+    }
+
+    nsString dumpID;
+    nsString browserDumpID;
+#ifdef MOZ_CRASHREPORTER
+    if (mCrashReporter && mCrashReporter->HasMinidump()) {
+        dumpID = mCrashReporter->MinidumpID();
+    }
+#endif
+    mPlugin->PluginCrashed(dumpID, browserDumpID);
 }
 
 PPluginInstanceParent*
 PluginModuleParent::AllocPPluginInstanceParent(const nsCString& aMimeType,
                                                const uint16_t& aMode,
                                                const InfallibleTArray<nsCString>& aNames,
                                                const InfallibleTArray<nsCString>& aValues)
 {
@@ -2983,55 +2993,16 @@ PluginModuleParent::RecvPluginHideWindow
     return IPC_OK();
 #else
     NS_NOTREACHED(
         "PluginInstanceParent::RecvPluginHideWindow not implemented!");
     return IPC_FAIL_NO_REASON(this);
 #endif
 }
 
-PCrashReporterParent*
-PluginModuleParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
-                                              uint32_t* processType)
-{
-    MOZ_CRASH("unreachable");
-}
-
-bool
-PluginModuleParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
-{
-    MOZ_CRASH("unreachable");
-}
-
-PCrashReporterParent*
-PluginModuleChromeParent::AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
-                                                    uint32_t* processType)
-{
-#ifdef MOZ_CRASHREPORTER
-    return new CrashReporterParent();
-#else
-    return nullptr;
-#endif
-}
-
-bool
-PluginModuleChromeParent::DeallocPCrashReporterParent(PCrashReporterParent* actor)
-{
-#ifdef MOZ_CRASHREPORTER
-#ifdef XP_WIN
-    mozilla::MutexAutoLock lock(mCrashReporterMutex);
-    if (actor == static_cast<PCrashReporterParent*>(mCrashReporter)) {
-        mCrashReporter = nullptr;
-    }
-#endif
-#endif
-    delete actor;
-    return true;
-}
-
 mozilla::ipc::IPCResult
 PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
 {
     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
 #if defined(XP_MACOSX)
     mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
     return IPC_OK();
 #else
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -32,21 +32,20 @@
 
 class nsIProfileSaveEvent;
 class nsPluginTag;
 
 namespace mozilla {
 #ifdef MOZ_GECKO_PROFILER
 class ProfileGatherer;
 #endif
-namespace dom {
-class PCrashReporterParent;
-class CrashReporterParent;
-} // namespace dom
 
+namespace ipc {
+class CrashReporterHost;
+} // namespace ipc
 namespace layers {
 class TextureClientRecycleAllocator;
 } // namespace layers
 
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 class BrowserStreamParent;
@@ -81,18 +80,16 @@ class PluginModuleParent
     : public PPluginModuleParent
     , public PluginLibrary
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , public CrashReporter::InjectorCrashCallback
 #endif
 {
 protected:
     typedef mozilla::PluginLibrary PluginLibrary;
-    typedef mozilla::dom::PCrashReporterParent PCrashReporterParent;
-    typedef mozilla::dom::CrashReporterParent CrashReporterParent;
 
     PPluginInstanceParent*
     AllocPPluginInstanceParent(const nsCString& aMimeType,
                                const uint16_t& aMode,
                                const InfallibleTArray<nsCString>& aNames,
                                const InfallibleTArray<nsCString>& aValues)
                                override;
 
@@ -163,22 +160,16 @@ protected:
     virtual mozilla::ipc::IPCResult
     RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
                          const int32_t& aX, const int32_t& aY,
                          const size_t& aWidth, const size_t& aHeight) override;
 
     virtual mozilla::ipc::IPCResult
     RecvPluginHideWindow(const uint32_t& aWindowId) override;
 
-    virtual PCrashReporterParent*
-    AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
-                              uint32_t* processType) override;
-    virtual bool
-    DeallocPCrashReporterParent(PCrashReporterParent* actor) override;
-
     virtual mozilla::ipc::IPCResult
     RecvSetCursor(const NSCursorInfo& aCursorInfo) override;
 
     virtual mozilla::ipc::IPCResult
     RecvShowCursor(const bool& aShow) override;
 
     virtual mozilla::ipc::IPCResult
     RecvPushCursor(const NSCursorInfo& aCursorInfo) override;
@@ -334,18 +325,16 @@ protected:
     bool mShutdown;
     bool mHadLocalInstance;
     bool mClearSiteDataSupported;
     bool mGetSitesWithDataSupported;
     NPNetscapeFuncs* mNPNIface;
     NPPluginFuncs* mNPPIface;
     nsNPAPIPlugin* mPlugin;
     ipc::TaskFactory<PluginModuleParent> mTaskFactory;
-    nsString mPluginDumpID;
-    nsString mBrowserDumpID;
     nsString mHangID;
     RefPtr<nsIObserver> mProfilerObserver;
     TimeDuration mTimeBlocked;
     nsCString mPluginName;
     nsCString mPluginVersion;
     int32_t mSandboxLevel;
     bool mIsFlashPlugin;
 
@@ -353,28 +342,38 @@ protected:
     // Dup of plugin's X socket, used to scope its resources to this
     // object instead of the plugin process's lifetime
     ScopedClose mPluginXSocketFdDup;
 #endif
 
     bool
     GetPluginDetails();
 
-    friend class mozilla::dom::CrashReporterParent;
     friend class mozilla::plugins::PluginAsyncSurrogate;
 
     bool              mIsStartingAsync;
     bool              mNPInitialized;
     bool              mIsNPShutdownPending;
     nsTArray<RefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
     nsresult          mAsyncNewRv;
     uint32_t          mRunID;
 
     RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocatorForDirectBitmap;
     RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocatorForDXGISurface;
+
+#ifdef MOZ_CRASHREPORTER
+    /**
+     * This mutex protects the crash reporter when the Plugin Hang UI event
+     * handler is executing off main thread. It is intended to protect both
+     * the mCrashReporter variable in addition to the CrashReporterHost object
+     * that mCrashReporter refers to.
+     */
+    mozilla::Mutex mCrashReporterMutex;
+    UniquePtr<ipc::CrashReporterHost> mCrashReporter;
+#endif // MOZ_CRASHREPORTER
 };
 
 class PluginModuleContentParent : public PluginModuleParent
 {
   public:
     explicit PluginModuleContentParent(bool aAllowAsyncInit);
 
     static PluginLibrary* LoadModule(uint32_t aPluginId, nsPluginTag* aPluginTag);
@@ -405,16 +404,17 @@ class PluginModuleContentParent : public
 
     uint32_t mPluginId;
 };
 
 class PluginModuleChromeParent
     : public PluginModuleParent
     , public mozilla::HangMonitor::Annotator
 {
+    friend class mozilla::ipc::CrashReporterHost;
   public:
     /**
      * LoadModule
      *
      * This may or may not launch a plugin child process,
      * and may or may not be very expensive.
      */
     static PluginLibrary* LoadModule(const char* aFilePath, uint32_t aPluginId,
@@ -521,25 +521,19 @@ private:
 
     virtual void
     AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) override;
 
     virtual bool ShouldContinueFromReplyTimeout() override;
 
 #ifdef MOZ_CRASHREPORTER
     void ProcessFirstMinidump();
-    void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
+    void WriteExtraDataForMinidump();
 #endif
 
-    virtual PCrashReporterParent*
-    AllocPCrashReporterParent(mozilla::dom::NativeThreadId* id,
-                              uint32_t* processType) override;
-    virtual bool
-    DeallocPCrashReporterParent(PCrashReporterParent* actor) override;
-
     PluginProcessParent* Process() const { return mSubprocess; }
     base::ProcessHandle ChildProcessHandle() { return mSubprocess->GetChildProcessHandle(); }
 
 #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
     virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) override;
 #else
     virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) override;
 #endif
@@ -550,30 +544,30 @@ private:
 
     virtual void ActorDestroy(ActorDestroyReason why) override;
 
     // aFilePath is UTF8, not native!
     explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId,
                                       int32_t aSandboxLevel,
                                       bool aAllowAsyncInit);
 
-    CrashReporterParent* CrashReporter();
-
     void CleanupFromTimeout(const bool aByHangUI);
 
     virtual void UpdatePluginTimeout() override;
 
 #ifdef MOZ_GECKO_PROFILER
     void InitPluginProfiling();
     void ShutdownPluginProfiling();
 #endif
 
     void RegisterSettingsCallbacks();
     void UnregisterSettingsCallbacks();
 
+    bool InitCrashReporter();
+
     virtual mozilla::ipc::IPCResult RecvNotifyContentModuleDestroyed() override;
 
     static void CachedSettingChanged(const char* aPref, void* aModule);
 
     virtual mozilla::ipc::IPCResult
     AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
                                         const bool& shouldRegister,
                                         NPError* result) override;
@@ -591,27 +585,16 @@ private:
         kHangUIDontShow = (1u << 3)
     };
     Atomic<uint32_t> mHangAnnotationFlags;
 #ifdef XP_WIN
     InfallibleTArray<float> mPluginCpuUsageOnHang;
     PluginHangUIParent *mHangUIParent;
     bool mHangUIEnabled;
     bool mIsTimerReset;
-#ifdef MOZ_CRASHREPORTER
-    /**
-     * This mutex protects the crash reporter when the Plugin Hang UI event
-     * handler is executing off main thread. It is intended to protect both
-     * the mCrashReporter variable in addition to the CrashReporterParent object
-     * that mCrashReporter refers to.
-     */
-    mozilla::Mutex mCrashReporterMutex;
-    CrashReporterParent* mCrashReporter;
-#endif // MOZ_CRASHREPORTER
-
 
     /**
      * Launches the Plugin Hang UI.
      *
      * @return true if plugin-hang-ui.exe has been successfully launched.
      *         false if the Plugin Hang UI is disabled, already showing,
      *               or the launch failed.
      */
@@ -620,17 +603,16 @@ private:
 
     /**
      * Finishes the Plugin Hang UI and cancels if it is being shown to the user.
      */
     void
     FinishHangUI();
 #endif
 
-    friend class mozilla::dom::CrashReporterParent;
     friend class mozilla::plugins::PluginAsyncSurrogate;
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     friend class mozilla::plugins::FinishInjectorInitTask;
 
     void InitializeInjector();
     void DoInjection(const nsAutoHandle& aSnapshot);
     static DWORD WINAPI GetToolhelpSnapshot(LPVOID aContext);
--- a/dom/storage/Storage.cpp
+++ b/dom/storage/Storage.cpp
@@ -175,17 +175,20 @@ Storage::Clear(nsIPrincipal& aSubjectPri
 
 namespace {
 
 class StorageNotifierRunnable : public Runnable
 {
 public:
   StorageNotifierRunnable(nsISupports* aSubject, const char16_t* aType,
                           bool aPrivateBrowsing)
-    : mSubject(aSubject), mType(aType), mPrivateBrowsing(aPrivateBrowsing)
+    : Runnable("StorageNotifierRunnable")
+    , mSubject(aSubject)
+    , mType(aType)
+    , mPrivateBrowsing(aPrivateBrowsing)
   { }
 
   NS_DECL_NSIRUNNABLE
 
 private:
   nsCOMPtr<nsISupports> mSubject;
   const char16_t* mType;
   const bool mPrivateBrowsing;
--- a/dom/storage/StorageCache.cpp
+++ b/dom/storage/StorageCache.cpp
@@ -243,36 +243,49 @@ StorageCache::Preload()
 
   sDatabase->AsyncPreload(this);
 }
 
 namespace {
 
 // This class is passed to timer as a tick observer.  It refers the cache
 // and keeps it alive for a time.
-class StorageCacheHolder : public nsITimerCallback
+class StorageCacheHolder : public nsITimerCallback, public nsINamed
 {
   virtual ~StorageCacheHolder() {}
 
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   Notify(nsITimer* aTimer) override
   {
     mCache = nullptr;
     return NS_OK;
   }
 
+  NS_IMETHOD
+  GetName(nsACString& aName) override
+  {
+    aName.AssignASCII("StorageCacheHolder_timer");
+    return NS_OK;
+  }
+
+  NS_IMETHOD
+  SetName(const char* aName) override
+  {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
   RefPtr<StorageCache> mCache;
 
 public:
   explicit StorageCacheHolder(StorageCache* aCache) : mCache(aCache) {}
 };
 
-NS_IMPL_ISUPPORTS(StorageCacheHolder, nsITimerCallback)
+NS_IMPL_ISUPPORTS(StorageCacheHolder, nsITimerCallback, nsINamed)
 
 } // namespace
 
 void
 StorageCache::KeepAlive()
 {
   // Missing reference back to the manager means the cache is not responsible
   // for its lifetime.  Used for keeping sessionStorage live forever.
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -346,17 +346,18 @@ nsBindingManager::AddToAttachedQueue(nsX
   return NS_OK;
 
 }
 
 void
 nsBindingManager::PostProcessAttachedQueueEvent()
 {
   mProcessAttachedQueueEvent =
-    NewRunnableMethod(this, &nsBindingManager::DoProcessAttachedQueue);
+    NewRunnableMethod("nsBindingManager::DoProcessAttachedQueue",
+                      this, &nsBindingManager::DoProcessAttachedQueue);
   nsresult rv = NS_DispatchToCurrentThread(mProcessAttachedQueueEvent);
   if (NS_SUCCEEDED(rv) && mDocument) {
     mDocument->BlockOnload();
   }
 }
 
 // static
 void
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -376,16 +376,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
+  NS_INTERFACE_MAP_ENTRY(nsINamed)
   NS_INTERFACE_MAP_ENTRY(nsISizeOfEventTarget)
 NS_INTERFACE_MAP_END_INHERITING(XMLHttpRequestEventTarget)
 
 NS_IMPL_ADDREF_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)
 NS_IMPL_RELEASE_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)
 
 NS_IMPL_EVENT_HANDLER(XMLHttpRequestMainThread, readystatechange)
 
@@ -3774,24 +3775,24 @@ XMLHttpRequestMainThread::BlobStoreCompl
   MOZ_ASSERT(mState != State::done);
 
   mResponseBlob = aBlob;
   mBlobStorage = nullptr;
 
   ChangeStateToDone();
 }
 
-nsresult
+NS_IMETHODIMP
 XMLHttpRequestMainThread::GetName(nsACString& aName)
 {
   aName.AssignLiteral("XMLHttpRequest");
   return NS_OK;
 }
 
-nsresult
+NS_IMETHODIMP
 XMLHttpRequestMainThread::SetName(const char* aName)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 // nsXMLHttpRequestXPCOMifier implementation
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequestXPCOMifier)
   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
--- a/gfx/ipc/GPUChild.cpp
+++ b/gfx/ipc/GPUChild.cpp
@@ -116,20 +116,23 @@ GPUChild::RecvGraphicsError(const nsCStr
     std::stringstream message;
     message << "GP+" << aError.get();
     lf->UpdateStringsVector(message.str());
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-GPUChild::RecvInitCrashReporter(Shmem&& aShmem)
+GPUChild::RecvInitCrashReporter(Shmem&& aShmem, const NativeThreadId& aThreadId)
 {
 #ifdef MOZ_CRASHREPORTER
-  mCrashReporter = MakeUnique<ipc::CrashReporterHost>(GeckoProcessType_GPU, aShmem);
+  mCrashReporter = MakeUnique<ipc::CrashReporterHost>(
+    GeckoProcessType_GPU,
+    aShmem,
+    aThreadId);
 #endif
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 GPUChild::RecvNotifyUiObservers(const nsCString& aTopic)
 {
   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
--- a/gfx/ipc/GPUChild.h
+++ b/gfx/ipc/GPUChild.h
@@ -37,17 +37,17 @@ public:
   void EnsureGPUReady();
 
   // gfxVarReceiver overrides.
   void OnVarChanged(const GfxVarUpdate& aVar) override;
 
   // PGPUChild overrides.
   mozilla::ipc::IPCResult RecvInitComplete(const GPUDeviceData& aData) override;
   mozilla::ipc::IPCResult RecvReportCheckerboard(const uint32_t& aSeverity, const nsCString& aLog) override;
-  mozilla::ipc::IPCResult RecvInitCrashReporter(Shmem&& shmem) override;
+  mozilla::ipc::IPCResult RecvInitCrashReporter(Shmem&& shmem, const NativeThreadId& aThreadId) override;
   mozilla::ipc::IPCResult RecvAccumulateChildHistogram(InfallibleTArray<Accumulation>&& aAccumulations) override;
   mozilla::ipc::IPCResult RecvAccumulateChildKeyedHistogram(InfallibleTArray<KeyedAccumulation>&& aAccumulations) override;
   mozilla::ipc::IPCResult RecvUpdateChildScalars(InfallibleTArray<ScalarAction>&& aScalarActions) override;
   mozilla::ipc::IPCResult RecvUpdateChildKeyedScalars(InfallibleTArray<KeyedScalarAction>&& aScalarActions) override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
   mozilla::ipc::IPCResult RecvGraphicsError(const nsCString& aError) override;
   mozilla::ipc::IPCResult RecvNotifyUiObservers(const nsCString& aTopic) override;
   mozilla::ipc::IPCResult RecvNotifyDeviceReset() override;
--- a/gfx/ipc/PGPU.ipdl
+++ b/gfx/ipc/PGPU.ipdl
@@ -10,16 +10,17 @@ include protocol PImageBridge;
 include protocol PVRManager;
 include protocol PVsyncBridge;
 include protocol PUiCompositorController;
 include protocol PVideoDecoderManager;
 
 using base::ProcessId from "base/process.h";
 using mozilla::TimeDuration from "mozilla/TimeStamp.h";
 using mozilla::CSSToLayoutDeviceScale from "Units.h";
+using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
 using mozilla::gfx::IntSize from "mozilla/gfx/2D.h";
 using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
 using mozilla::Telemetry::Accumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedAccumulation from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::ScalarAction from "mozilla/TelemetryComms.h";
 using mozilla::Telemetry::KeyedScalarAction from "mozilla/TelemetryComms.h";
 
 namespace mozilla {
@@ -97,17 +98,17 @@ child:
   async InitComplete(GPUDeviceData data);
 
   // Sent when APZ detects checkerboarding and apz checkerboard reporting is enabled.
   async ReportCheckerboard(uint32_t severity, nsCString log);
 
   // Graphics errors, analogous to PContent::GraphicsError
   async GraphicsError(nsCString aError);
 
-  async InitCrashReporter(Shmem shmem);
+  async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
 
   // Have a message be broadcasted to the UI process by the UI process
   // observer service.
   async NotifyUiObservers(nsCString aTopic);
 
   // Messages for reporting telemetry to the UI process.
   async AccumulateChildHistogram(Accumulation[] accumulations);
   async AccumulateChildKeyedHistogram(KeyedAccumulation[] accumulations);
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -539,37 +539,16 @@ public:
 
   ScreenRotation GetScreenRotation() const {
     return mScreenRotation;
   }
   void SetScreenRotation(ScreenRotation aRotation) {
     mScreenRotation = aRotation;
   }
 
-  TimeStamp GetCompositionTime() const {
-    return mCompositionTime;
-  }
-  void SetCompositionTime(TimeStamp aTimeStamp) {
-    mCompositionTime = aTimeStamp;
-    if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
-        mCompositionTime >= mCompositeUntilTime) {
-      mCompositeUntilTime = TimeStamp();
-    }
-  }
-
-  virtual void CompositeUntil(TimeStamp aTimeStamp) {
-    if (mCompositeUntilTime.IsNull() ||
-        mCompositeUntilTime < aTimeStamp) {
-      mCompositeUntilTime = aTimeStamp;
-    }
-  }
-  TimeStamp GetCompositeUntilTime() const {
-    return mCompositeUntilTime;
-  }
-
   // A stale Compositor has no CompositorBridgeParent; it will not process
   // frames and should not be used.
   void SetInvalid();
   virtual bool IsValid() const;
   CompositorBridgeParent* GetCompositorBridgeParent() const {
     return mParent;
   }
 
@@ -649,27 +628,16 @@ protected:
    */
   nsTArray<RefPtr<TextureHost>> mNotifyNotUsedAfterComposition;
 
   /**
    * Last Composition end time.
    */
   TimeStamp mLastCompositionEndTime;
 
-  /**
-   * Render time for the current composition.
-   */
-  TimeStamp mCompositionTime;
-  /**
-   * When nonnull, during rendering, some compositable indicated that it will
-   * change its rendering at this time. In order not to miss it, we composite
-   * on every vsync until this time occurs (this is the latest such time).
-   */
-  TimeStamp mCompositeUntilTime;
-
   uint32_t mCompositorID;
   DiagnosticTypes mDiagnosticTypes;
   CompositorBridgeParent* mParent;
 
   /**
    * We keep track of the total number of pixels filled as we composite the
    * current frame. This value is an approximation and is not accurate,
    * especially in the presence of transforms.
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -73,16 +73,17 @@ class DrawTarget;
 namespace layers {
 
 class Animation;
 class AnimationData;
 class AsyncCanvasRenderer;
 class AsyncPanZoomController;
 class BasicLayerManager;
 class ClientLayerManager;
+class HostLayerManager;
 class Layer;
 class LayerMetricsWrapper;
 class PaintedLayer;
 class ContainerLayer;
 class ImageLayer;
 class ColorLayer;
 class CompositorBridgeChild;
 class TextLayer;
@@ -209,16 +210,18 @@ public:
   virtual LayerManagerComposite* AsLayerManagerComposite()
   { return nullptr; }
 
   virtual ClientLayerManager* AsClientLayerManager()
   { return nullptr; }
 
   virtual BasicLayerManager* AsBasicLayerManager()
   { return nullptr; }
+  virtual HostLayerManager* AsHostLayerManager()
+  { return nullptr; }
 
   virtual WebRenderLayerManager* AsWebRenderLayerManager()
   { return nullptr; }
 
   /**
    * Returns true if this LayerManager is owned by an nsIWidget,
    * and is used for drawing into the widget.
    */
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -137,17 +137,19 @@ ClientLayerManager::Destroy()
 
   if (mTransactionIdAllocator) {
     // Make sure to notify the refresh driver just in case it's waiting on a
     // pending transaction. Do this at the top of the event loop so we don't
     // cause a paint to occur during compositor shutdown.
     RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
     uint64_t id = mLatestTransactionId;
 
-    RefPtr<Runnable> task = NS_NewRunnableFunction([allocator, id] () -> void {
+    RefPtr<Runnable> task = NS_NewRunnableFunction(
+      "TransactionIdAllocator::NotifyTransactionCompleted",
+      [allocator, id] () -> void {
       allocator->NotifyTransactionCompleted(id);
     });
     NS_DispatchToMainThread(task.forget());
   }
 
   // Forget the widget pointer in case we outlive our owning widget.
   mWidget = nullptr;
 }
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -142,23 +142,16 @@ private:
   }
 
   /// The normal way to destroy the actor.
   ///
   /// This will asynchronously send a Destroy message to the parent actor, whom
   /// will send the delete message.
   void Destroy(const TextureDeallocParams& aParams);
 
-  /// The ugly and slow way to destroy the actor.
-  ///
-  /// This will block until the Parent actor has handled the Destroy message,
-  /// and then start the asynchronous handshake (and destruction will already
-  /// be done on the parent side, when the async part happens).
-  void DestroySynchronously(const TextureDeallocParams& aParams);
-
   // This lock is used order to prevent several threads to access the
   // TextureClient's data concurrently. In particular, it prevents shutdown
   // code to destroy a texture while another thread is reading or writing into
   // it.
   // In most places, the lock is held in short and bounded scopes in which we
   // don't block on any other resource. There are few exceptions to this, which
   // are discussed below.
   //
@@ -274,57 +267,36 @@ TextureChild::Destroy(const TextureDeall
 {
   MOZ_ASSERT(!mOwnerCalledDestroy);
   if (mOwnerCalledDestroy) {
     return;
   }
 
   mOwnerCalledDestroy = true;
 
+  if (!IPCOpen()) {
+    DestroyTextureData(
+      aParams.data,
+      aParams.allocator,
+      aParams.clientDeallocation,
+      mMainThreadOnly);
+    return;
+  }
+
   // DestroyTextureData will be called by TextureChild::ActorDestroy
   mTextureData = aParams.data;
   mOwnsTextureData = aParams.clientDeallocation;
 
   if (!mCompositableForwarder ||
-      !mCompositableForwarder->DestroyInTransaction(this, false))
+      !mCompositableForwarder->DestroyInTransaction(this))
   {
     this->SendDestroy();
   }
 }
 
-void
-TextureChild::DestroySynchronously(const TextureDeallocParams& aParams)
-{
-  MOZ_PERFORMANCE_WARNING("gfx", "TextureClient/Host pair requires synchronous deallocation");
-
-  MOZ_ASSERT(!mOwnerCalledDestroy);
-  if (mOwnerCalledDestroy) {
-    return;
-  }
-
-  mOwnerCalledDestroy = true;
-
-  DestroyTextureData(
-    aParams.data,
-    aParams.allocator,
-    aParams.clientDeallocation,
-    mMainThreadOnly);
-
-  if (!IPCOpen()) {
-    return;
-  }
-
-  if (!mCompositableForwarder ||
-      !mCompositableForwarder->DestroyInTransaction(this, true))
-  {
-    this->SendDestroySync();
-    this->SendDestroy();
-  }
-}
-
 /* static */ Atomic<uint64_t> TextureClient::sSerialCounter(0);
 
 void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
                                         ReentrantMonitor* aBarrier, bool* aDone)
 {
   DeallocateTextureClient(params);
   ReentrantMonitorAutoEnter autoMon(*aBarrier);
   *aDone = true;
@@ -396,24 +368,20 @@ DeallocateTextureClient(TextureDeallocPa
     // our data.
     bool shouldDeallocate = !params.workAroundSharedSurfaceOwnershipIssue;
     DestroyTextureData(params.data, params.allocator,
                        shouldDeallocate,
                        false);  // main-thread deallocation
     return;
   }
 
-  if (params.syncDeallocation || !actor->IPCOpen()) {
-    actor->DestroySynchronously(params);
-  } else {
-    actor->Destroy(params);
-  }
+  actor->Destroy(params);
 }
 
-void TextureClient::Destroy(bool aForceSync)
+void TextureClient::Destroy()
 {
   if (mActor && !mIsLocked) {
     mActor->Lock();
   }
 
   mBorrowedDrawTarget = nullptr;
   mReadLock = nullptr;
 
@@ -439,17 +407,17 @@ void TextureClient::Destroy(bool aForceS
     if (mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
       params.data = nullptr;
     } else {
       params.data = data;
     }
     // At the moment we always deallocate synchronously when deallocating on the
     // client side, but having asynchronous deallocate in some of the cases will
     // be a worthwhile optimization.
-    params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync;
+    params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
 
     // Release the lock before calling DeallocateTextureClient because the latter
     // may wait for the main thread which could create a dead-lock.
 
     if (actor) {
       actor->Unlock();
     }
 
@@ -626,17 +594,17 @@ TextureClient::SerializeReadLock(ReadLoc
   } else {
     aDescriptor = null_t();
   }
 }
 
 TextureClient::~TextureClient()
 {
   mReadLock = nullptr;
-  Destroy(false);
+  Destroy();
 }
 
 void
 TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
 {
   MOZ_ASSERT(IsValid());
   MOZ_ASSERT(mIsLocked);
   MOZ_ASSERT(aSurface);
@@ -1658,20 +1626,20 @@ int32_t
 ShmemTextureReadLock::ReadUnlock() {
   if (!mAllocSuccess) {
     return 0;
   }
   ShmReadLockInfo* info = GetShmReadLockInfoPtr();
   int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
   MOZ_ASSERT(readCount >= 0);
   if (readCount <= 0) {
-    if (mClientAllocator) {
+    if (mClientAllocator && mClientAllocator->GetTileLockAllocator()) {
       mClientAllocator->GetTileLockAllocator()->DeallocShmemSection(mShmemSection);
     } else {
-      // we are on the compositor process
+      // we are on the compositor process, or IPC is down.
       FixedSizeSmallShmemSectionAllocator::FreeShmemSection(mShmemSection);
     }
   }
   return readCount;
 }
 
 int32_t
 ShmemTextureReadLock::GetReadCount() {
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -583,20 +583,18 @@ public:
   PTextureChild* GetIPDLActor();
 
   /**
    * Triggers the destruction of the shared data and the corresponding TextureHost.
    *
    * If the texture flags contain TextureFlags::DEALLOCATE_CLIENT, the destruction
    * will be synchronously coordinated with the compositor side, otherwise it
    * will be done asynchronously.
-   * If sync is true, the destruction will be synchronous regardless of the
-   * texture's flags (bad for performance, use with care).
    */
-  void Destroy(bool sync = false);
+  void Destroy();
 
   /**
    * Track how much of this texture is wasted.
    * For example we might allocate a 256x256 tile but only use 10x10.
    */
   void SetWaste(int aWasteArea) {
     mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
   }
--- a/gfx/layers/composite/CompositableHost.cpp
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -156,10 +156,19 @@ CompositableHost::DumpTextureHost(std::s
   }
   RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
   if (!dSurf) {
     return;
   }
   aStream << gfxUtils::GetAsDataURI(dSurf).get();
 }
 
+HostLayerManager*
+CompositableHost::GetLayerManager() const
+{
+  if (!mLayer || !mLayer->Manager()) {
+    return nullptr;
+  }
+  return mLayer->Manager()->AsHostLayerManager();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/composite/CompositableHost.h
+++ b/gfx/layers/composite/CompositableHost.h
@@ -232,16 +232,19 @@ public:
   /// Called when shutting down the layer tree.
   /// This is a good place to clear all potential gpu resources before the widget
   /// is is destroyed.
   virtual void CleanupResources() {}
 
   virtual void BindTextureSource() {}
 
 protected:
+  HostLayerManager* GetLayerManager() const;
+
+protected:
   TextureInfo mTextureInfo;
   AsyncCompositableRef mAsyncRef;
   uint64_t mCompositorID;
   RefPtr<Compositor> mCompositor;
   Layer* mLayer;
   uint32_t mFlashCounter; // used when the pref "layers.flash-borders" is true.
   bool mAttached;
   bool mKeepAttached;
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -72,27 +72,29 @@ ImageHost::UseTextureHost(const nsTArray
   newImages.Clear();
 
   // If we only have one image we can upload it right away, otherwise we'll upload
   // on-demand during composition after we have picked the proper timestamp.
   if (mImages.Length() == 1) {
     SetCurrentTextureHost(mImages[0].mTextureHost);
   }
 
+  HostLayerManager* lm = GetLayerManager();
+
   // Video producers generally send replacement images with the same frameID but
   // slightly different timestamps in order to sync with the audio clock. This
   // means that any CompositeUntil() call we made in Composite() may no longer
   // guarantee that we'll composite until the next frame is ready. Fix that here.
-  if (GetCompositor() && mLastFrameID >= 0) {
+  if (lm && mLastFrameID >= 0) {
     for (size_t i = 0; i < mImages.Length(); ++i) {
       bool frameComesAfter = mImages[i].mFrameID > mLastFrameID ||
                              mImages[i].mProducerID != mLastProducerID;
       if (frameComesAfter && !mImages[i].mTimeStamp.IsNull()) {
-        GetCompositor()->CompositeUntil(mImages[i].mTimeStamp +
-                                        TimeDuration::FromMilliseconds(BIAS_TIME_MS));
+        lm->CompositeUntil(mImages[i].mTimeStamp +
+                           TimeDuration::FromMilliseconds(BIAS_TIME_MS));
         break;
       }
     }
   }
 }
 
 void
 ImageHost::SetCurrentTextureHost(TextureHost* aTexture)
@@ -150,18 +152,18 @@ ImageHost::RemoveTextureHost(TextureHost
     }
   }
 }
 
 TimeStamp
 ImageHost::GetCompositionTime() const
 {
   TimeStamp time;
-  if (GetCompositor()) {
-    time = GetCompositor()->GetCompositionTime();
+  if (HostLayerManager* lm = GetLayerManager()) {
+    time = lm->GetCompositionTime();
   }
   return time;
 }
 
 TextureHost*
 ImageHost::GetAsTextureHost(IntRect* aPictureRect)
 {
   TimedImage* img = ChooseImage();
@@ -192,30 +194,28 @@ ImageHost::Composite(LayerComposite* aLa
                      EffectChain& aEffectChain,
                      float aOpacity,
                      const gfx::Matrix4x4& aTransform,
                      const gfx::SamplingFilter aSamplingFilter,
                      const gfx::IntRect& aClipRect,
                      const nsIntRegion* aVisibleRegion,
                      const Maybe<gfx::Polygon>& aGeometry)
 {
-  if (!GetCompositor()) {
-    // should only happen when a tab is dragged to another window and
-    // async-video is still sending frames but we haven't attached the
-    // set the new compositor yet.
+  HostLayerManager* lm = GetLayerManager();
+  if (!lm) {
     return;
   }
 
   int imageIndex = ChooseImageIndex();
   if (imageIndex < 0) {
     return;
   }
 
   if (uint32_t(imageIndex) + 1 < mImages.Length()) {
-    GetCompositor()->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
+    lm->CompositeUntil(mImages[imageIndex + 1].mTimeStamp + TimeDuration::FromMilliseconds(BIAS_TIME_MS));
   }
 
   TimedImage* img = &mImages[imageIndex];
   img->mTextureHost->SetCompositor(GetCompositor());
   SetCurrentTextureHost(img->mTextureHost);
 
   {
     AutoLockCompositableHost autoLock(this);
@@ -255,17 +255,17 @@ ImageHost::Composite(LayerComposite* aLa
     }
 
     if (mLastFrameID != img->mFrameID || mLastProducerID != img->mProducerID) {
       if (mAsyncRef) {
         ImageCompositeNotificationInfo info;
         info.mImageBridgeProcessId = mAsyncRef.mProcessId;
         info.mNotification = ImageCompositeNotification(
           mAsyncRef.mHandle,
-          img->mTimeStamp, GetCompositor()->GetCompositionTime(),
+          img->mTimeStamp, lm->GetCompositionTime(),
           img->mFrameID, img->mProducerID);
         static_cast<LayerManagerComposite*>(aLayer->GetLayerManager())->
             AppendImageCompositeNotification(info);
       }
       mLastFrameID = img->mFrameID;
       mLastProducerID = img->mProducerID;
     }
     aEffectChain.mPrimaryEffect = effect;
@@ -332,17 +332,17 @@ ImageHost::Composite(LayerComposite* aLa
   }
 
   // Update mBias last. This can change which frame ChooseImage(Index) would
   // return, and we don't want to do that until we've finished compositing
   // since callers of ChooseImage(Index) assume the same image will be chosen
   // during a given composition. This must happen after autoLock's
   // destructor!
   mBias = UpdateBias(
-      GetCompositor()->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
+      lm->GetCompositionTime(), mImages[imageIndex].mTimeStamp,
       uint32_t(imageIndex + 1) < mImages.Length() ?
           mImages[imageIndex + 1].mTimeStamp : TimeStamp(),
       mBias);
 }
 
 void
 ImageHost::SetCompositor(Compositor* aCompositor)
 {
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -26,16 +26,17 @@
 #include "nsRegionFwd.h"                // for nsIntRegion
 #include "nscore.h"                     // for nsACString
 
 namespace mozilla {
 namespace layers {
 
 class Compositor;
 struct EffectChain;
+class HostLayerManager;
 
 /**
  * ImageHost. Works with ImageClientSingle and ImageClientBuffered
  */
 class ImageHost : public CompositableHost,
                   public ImageComposite
 {
 public:
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -406,17 +406,17 @@ LayerManagerComposite::EndTransaction(co
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
   // Set composition timestamp here because we need it in
   // ComputeEffectiveTransforms (so the correct video frame size is picked) and
   // also to compute invalid regions properly.
-  mCompositor->SetCompositionTime(aTimeStamp);
+  SetCompositionTime(aTimeStamp);
 
   if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) {
     MOZ_ASSERT(!aTimeStamp.IsNull());
     UpdateAndRender();
     mCompositor->FlushPendingNotifyNotUsed();
   } else {
     // Modified the layer tree.
     mGeometryChanged = true;
@@ -1405,16 +1405,22 @@ bool
 LayerManagerComposite::AsyncPanZoomEnabled() const
 {
   if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) {
     return bridge->GetOptions().UseAPZ();
   }
   return false;
 }
 
+bool
+LayerManagerComposite::AlwaysScheduleComposite() const
+{
+  return !!(mCompositor->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS);
+}
+
 nsIntRegion
 LayerComposite::GetFullyRenderedRegion() {
   if (TiledContentHost* tiled = GetCompositableHost() ? GetCompositableHost()->AsTiledContentHost()
                                                         : nullptr) {
     nsIntRegion shadowVisibleRegion = GetShadowVisibleRegion().ToUnknownRegion();
     // Discard the region which hasn't been drawn yet when doing
     // progressive drawing. Note that if the shadow visible region
     // shrunk the tiled valig region may not have discarded this yet.
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -121,16 +121,20 @@ public:
   virtual void UpdateRenderBounds(const gfx::IntRect& aRect) {}
 
   // Called by CompositorBridgeParent when a new compositor has been created due
   // to a device reset. The layer manager must clear any cached resources
   // attached to the old compositor, and make a best effort at ignoring
   // layer or texture updates against the old compositor.
   virtual void ChangeCompositor(Compositor* aNewCompositor) = 0;
 
+  virtual HostLayerManager* AsHostLayerManager() override {
+    return this;
+  }
+
   void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
   {
     aNotifications->AppendElements(Move(mImageCompositeNotifications));
   }
 
   /**
    * LayerManagerComposite provides sophisticated debug overlays
    * that can request a next frame.
@@ -153,30 +157,61 @@ public:
     }
   }
 
   // Indicate that we need to composite even if nothing in our layers has
   // changed, so that the widget can draw something different in its window
   // overlay.
   void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
 
+  void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
 
-  void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
+  virtual bool AlwaysScheduleComposite() const {
+    return false;
+  }
+
+  TimeStamp GetCompositionTime() const {
+    return mCompositionTime;
+  }
+  void SetCompositionTime(TimeStamp aTimeStamp) {
+    mCompositionTime = aTimeStamp;
+    if (!mCompositionTime.IsNull() && !mCompositeUntilTime.IsNull() &&
+        mCompositionTime >= mCompositeUntilTime) {
+      mCompositeUntilTime = TimeStamp();
+    }
+  }
+  void CompositeUntil(TimeStamp aTimeStamp) {
+    if (mCompositeUntilTime.IsNull() ||
+        mCompositeUntilTime < aTimeStamp) {
+      mCompositeUntilTime = aTimeStamp;
+    }
+  }
+  TimeStamp GetCompositeUntilTime() const {
+    return mCompositeUntilTime;
+  }
 
 protected:
   bool mDebugOverlayWantsNextFrame;
   nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
   // Testing property. If hardware composer is supported, this will return
   // true if the last frame was deemed 'too complicated' to be rendered.
   float mWarningLevel;
   mozilla::TimeStamp mWarnTime;
 
   bool mWindowOverlayChanged;
   TimeDuration mLastPaintTime;
   TimeStamp mRenderStartTime;
+
+  // Render time for the current composition.
+  TimeStamp mCompositionTime;
+
+  // When nonnull, during rendering, some compositable indicated that it will
+  // change its rendering at this time. In order not to miss it, we composite
+  // on every vsync until this time occurs (this is the latest such time).
+  TimeStamp mCompositeUntilTime;
 };
 
 // A layer manager implementation that uses the Compositor API
 // to render layers.
 class LayerManagerComposite final : public HostLayerManager
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::IntSize IntSize;
@@ -243,16 +278,18 @@ public:
 
   virtual bool AreComponentAlphaLayersEnabled() override;
 
   virtual already_AddRefed<DrawTarget>
     CreateOptimalMaskDrawTarget(const IntSize &aSize) override;
 
   virtual const char* Name() const override { return ""; }
 
+  bool AlwaysScheduleComposite() const override;
+
   /**
    * Post-processes layers before composition. This performs the following:
    *
    *   - Applies occlusion culling. This restricts the shadow visible region
    *     of layers that are covered with opaque content.
    *     |aOpaqueRegion| is the region already known to be covered with opaque
    *     content, in the post-transform coordinate space of aLayer.
    *
--- a/gfx/layers/composite/TextureHost.cpp
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -76,21 +76,16 @@ public:
   virtual mozilla::ipc::IPCResult RecvRecycleTexture(const TextureFlags& aTextureFlags) override;
 
   TextureHost* GetTextureHost() { return mTextureHost; }
 
   virtual void Destroy() override;
 
   uint64_t GetSerial() const { return mSerial; }
 
-  virtual mozilla::ipc::IPCResult RecvDestroySync() override {
-    DestroyIfNeeded();
-    return IPC_OK();
-  }
-
   HostIPCAllocator* mSurfaceAllocator;
   RefPtr<TextureHost> mTextureHost;
   // mSerial is unique in TextureClient's process.
   const uint64_t mSerial;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 PTextureParent*
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -134,22 +134,27 @@ TiledContentHost::Detach(Layer* aLayer,
   }
   CompositableHost::Detach(aLayer,aFlags);
 }
 
 bool
 TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
                                       const SurfaceDescriptorTiles& aTiledDescriptor)
 {
+  HostLayerManager* lm = GetLayerManager();
+  if (!lm) {
+    return false;
+  }
+
   if (aTiledDescriptor.resolution() < 1) {
-    if (!mLowPrecisionTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
+    if (!mLowPrecisionTiledBuffer.UseTiles(aTiledDescriptor, lm, aAllocator)) {
       return false;
     }
   } else {
-    if (!mTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
+    if (!mTiledBuffer.UseTiles(aTiledDescriptor, lm, aAllocator)) {
       return false;
     }
   }
   return true;
 }
 
 void
 UseTileTexture(CompositableTextureHostRef& aTexture,
@@ -240,26 +245,26 @@ public:
 
 protected:
   nsTArray<TileHost> mTiles;
   size_t mFirstPossibility;
 };
 
 bool
 TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
-                                    Compositor* aCompositor,
+                                    HostLayerManager* aLayerManager,
                                     ISurfaceAllocator* aAllocator)
 {
   if (mResolution != aTiles.resolution() ||
       aTiles.tileSize() != mTileSize) {
     Clear();
   }
   MOZ_ASSERT(aAllocator);
-  MOZ_ASSERT(aCompositor);
-  if (!aAllocator || !aCompositor) {
+  MOZ_ASSERT(aLayerManager);
+  if (!aAllocator || !aLayerManager) {
     return false;
   }
 
   if (aTiles.resolution() == 0 || IsNaN(aTiles.resolution())) {
     // There are divisions by mResolution so this protects the compositor process
     // against malicious content processes and fuzzing.
     return false;
   }
@@ -289,17 +294,17 @@ TiledLayerBufferComposite::UseTiles(cons
         tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
         "Unrecognised tile descriptor type");
       continue;
     }
 
     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
 
     tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
-    tile.mTextureHost->SetCompositor(aCompositor);
+    tile.mTextureHost->SetCompositor(aLayerManager->GetCompositor());
     tile.mTextureHost->DeserializeReadLock(texturedDesc.sharedLock(), aAllocator);
 
     if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
       tile.mTextureHostOnWhite = TextureHost::AsTextureHost(
         texturedDesc.textureOnWhite().get_PTextureParent()
       );
       tile.mTextureHostOnWhite->DeserializeReadLock(
         texturedDesc.sharedLockOnWhite(), aAllocator
@@ -317,18 +322,18 @@ TiledLayerBufferComposite::UseTiles(cons
 
     if (aTiles.isProgressive() &&
         texturedDesc.wasPlaceholder())
     {
       // This is a progressive paint, and the tile used to be a placeholder.
       // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled)
       tile.mFadeStart = TimeStamp::Now();
 
-      aCompositor->CompositeUntil(tile.mFadeStart +
-        TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration()));
+      aLayerManager->CompositeUntil(
+        tile.mFadeStart + TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration()));
     }
   }
 
   // Step 2, attempt to recycle unused texture sources from the old tile set into new tiles.
   //
   // For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
   // to ensure that any implicit locking on the old gralloc image is released.
   for (TileHost& tile : mRetainedTiles) {
@@ -347,23 +352,23 @@ TiledLayerBufferComposite::UseTiles(cons
     }
 
     const TileDescriptor& tileDesc = tileDescriptors[i];
     const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
 
     UseTileTexture(tile.mTextureHost,
                    tile.mTextureSource,
                    texturedDesc.updateRect(),
-                   aCompositor);
+                   aLayerManager->GetCompositor());
 
     if (tile.mTextureHostOnWhite) {
       UseTileTexture(tile.mTextureHostOnWhite,
                      tile.mTextureSourceOnWhite,
                      texturedDesc.updateRect(),
-                     aCompositor);
+                     aLayerManager->GetCompositor());
     }
   }
 
   mTiles = newTiles;
   mTileSize = aTiles.tileSize();
   mTileOrigin = aTiles.tileOrigin();
   mValidRegion = aTiles.validRegion();
   mResolution = aTiles.resolution();
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -120,17 +120,17 @@ class TiledLayerBufferComposite
 {
   friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
 
 public:
   TiledLayerBufferComposite();
   ~TiledLayerBufferComposite();
 
   bool UseTiles(const SurfaceDescriptorTiles& aTileDescriptors,
-                Compositor* aCompositor,
+                HostLayerManager* aLayerManager,
                 ISurfaceAllocator* aAllocator);
 
   void Clear();
 
   TileHost GetPlaceholderTile() const { return TileHost(); }
 
   // Stores the absolute resolution of the containing frame, calculated
   // by the sum of the resolutions of all parent layers' FrameMetrics.
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -67,17 +67,17 @@ public:
    * Communicate to the compositor that aRegion in the texture identified by
    * aCompositable and aIdentifier has been updated to aThebesBuffer.
    */
   virtual void UpdateTextureRegion(CompositableClient* aCompositable,
                                    const ThebesBufferData& aThebesBufferData,
                                    const nsIntRegion& aUpdatedRegion) = 0;
 
   virtual void ReleaseCompositable(const CompositableHandle& aHandle) = 0;
-  virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) = 0;
+  virtual bool DestroyInTransaction(PTextureChild* aTexture) = 0;
 
   /**
    * Tell the CompositableHost on the compositor side to remove the texture
    * from the CompositableHost.
    * This function does not delete the TextureHost corresponding to the
    * TextureClient passed in parameter.
    * When the TextureClient has TEXTURE_DEALLOCATE_CLIENT flag,
    * the transaction becomes synchronous.
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -1007,17 +1007,16 @@ CompositorBridgeChild::ClearTexturePool(
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     mTexturePools[i]->Clear();
   }
 }
 
 FixedSizeSmallShmemSectionAllocator*
 CompositorBridgeChild::GetTileLockAllocator()
 {
-  MOZ_ASSERT(IPCOpen());
   if (!IPCOpen()) {
     return nullptr;
   }
 
   if (!mSectionAllocator) {
     mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this);
   }
   return mSectionAllocator;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1002,55 +1002,52 @@ CompositorBridgeParent::CompositeToTarge
   mLayerManager->SetDebugOverlayWantsNextFrame(false);
   mLayerManager->EndTransaction(time);
 
   if (!aTarget) {
     TimeStamp end = TimeStamp::Now();
     DidComposite(start, end);
   }
 
-  if (mCompositor) {
-    // We're not really taking advantage of the stored composite-again-time here.
-    // We might be able to skip the next few composites altogether. However,
-    // that's a bit complex to implement and we'll get most of the advantage
-    // by skipping compositing when we detect there's nothing invalid. This is why
-    // we do "composite until" rather than "composite again at".
-    if (!mCompositor->GetCompositeUntilTime().IsNull() ||
-        mLayerManager->DebugOverlayWantsNextFrame()) {
+  // We're not really taking advantage of the stored composite-again-time here.
+  // We might be able to skip the next few composites altogether. However,
+  // that's a bit complex to implement and we'll get most of the advantage
+  // by skipping compositing when we detect there's nothing invalid. This is why
+  // we do "composite until" rather than "composite again at".
+  //
+  // TODO(bug 1328602) Figure out what we should do here with the render thread.
+  if (!mLayerManager->GetCompositeUntilTime().IsNull() ||
+      mLayerManager->DebugOverlayWantsNextFrame())
+  {
       ScheduleComposition();
-    }
-  } else {
-    // TODO(bug 1328602) Figure out what we should do here with the render thread.
   }
 
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime();
   TimeDuration frameBudget = TimeDuration::FromMilliseconds(15);
   int32_t frameRate = CalculateCompositionFrameRate();
   if (frameRate > 0) {
     frameBudget = TimeDuration::FromSeconds(1.0 / frameRate);
   }
   if (executionTime > frameBudget) {
     printf_stderr("Compositor: Composite execution took %4.1f ms\n",
                   executionTime.ToMilliseconds());
   }
 #endif
 
   // 0 -> Full-tilt composite
-  if (gfxPrefs::LayersCompositionFrameRate() == 0
-    || mLayerManager->GetCompositor()->GetDiagnosticTypes() & DiagnosticTypes::FLASH_BORDERS) {
+  if (gfxPrefs::LayersCompositionFrameRate() == 0 ||
+      mLayerManager->AlwaysScheduleComposite())
+  {
     // Special full-tilt composite mode for performance testing
     ScheduleComposition();
   }
 
-  if (mCompositor) {
-    mCompositor->SetCompositionTime(TimeStamp());
-  } else {
-    // TODO(bug 1328602) Need an equivalent that works with the rende thread.
-  }
+  // TODO(bug 1328602) Need an equivalent that works with the rende thread.
+  mLayerManager->SetCompositionTime(TimeStamp());
 
   mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start);
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvRemotePluginsReady()
 {
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -57,18 +57,17 @@ using namespace mozilla::gfx;
 using namespace mozilla::media;
 
 typedef std::vector<CompositableOperation> OpVector;
 typedef nsTArray<OpDestroy> OpDestroyVector;
 
 struct CompositableTransaction
 {
   CompositableTransaction()
-  : mSwapRequired(false)
-  , mFinished(true)
+  : mFinished(true)
   {}
   ~CompositableTransaction()
   {
     End();
   }
   bool Finished() const
   {
     return mFinished;
@@ -76,42 +75,31 @@ struct CompositableTransaction
   void Begin()
   {
     MOZ_ASSERT(mFinished);
     mFinished = false;
   }
   void End()
   {
     mFinished = true;
-    mSwapRequired = false;
     mOperations.clear();
     mDestroyedActors.Clear();
   }
   bool IsEmpty() const
   {
     return mOperations.empty() && mDestroyedActors.IsEmpty();
   }
   void AddNoSwapEdit(const CompositableOperation& op)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mOperations.push_back(op);
   }
-  void AddEdit(const CompositableOperation& op)
-  {
-    AddNoSwapEdit(op);
-    MarkSyncTransaction();
-  }
-  void MarkSyncTransaction()
-  {
-    mSwapRequired = true;
-  }
 
   OpVector mOperations;
   OpDestroyVector mDestroyedActors;
-  bool mSwapRequired;
   bool mFinished;
 };
 
 struct AutoEndTransaction {
   explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
   ~AutoEndTransaction() { mTxn->End(); }
   CompositableTransaction* mTxn;
 };
@@ -550,28 +538,19 @@ ImageBridgeChild::EndTransaction()
   if (!mTxn->mOperations.empty()) {
     cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
   }
 
   if (!IsSameProcess()) {
     ShadowLayerForwarder::PlatformSyncBeforeUpdate();
   }
 
-  if (mTxn->mSwapRequired) {
-    if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
-      NS_WARNING("could not send async texture transaction");
-      return;
-    }
-  } else {
-    // If we don't require a swap we can call SendUpdateNoSwap which
-    // assumes that aReplies is empty (DEBUG assertion)
-    if (!SendUpdateNoSwap(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
-      NS_WARNING("could not send async texture transaction (no swap)");
-      return;
-    }
+  if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
+    NS_WARNING("could not send async texture transaction");
+    return;
   }
 }
 
 void
 ImageBridgeChild::SendImageBridgeThreadId()
 {
 }
 
@@ -1060,64 +1039,53 @@ ImageBridgeChild::CreateTexture(const Su
                                 TextureFlags aFlags,
                                 uint64_t aSerial)
 {
   MOZ_ASSERT(CanSend());
   return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
 }
 
 static bool
-IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously)
+IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op)
 {
   if (aTxn->Finished()) {
     return false;
   }
 
   aTxn->mDestroyedActors.AppendElement(op);
-
-  if (synchronously) {
-    aTxn->MarkSyncTransaction();
-  }
-
   return true;
 }
 
 bool
-ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
+ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture)
 {
-  return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
+  return IBCAddOpDestroy(mTxn, OpDestroy(aTexture));
 }
 
 bool
 ImageBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
 {
-  return IBCAddOpDestroy(mTxn, OpDestroy(aHandle), false);
+  return IBCAddOpDestroy(mTxn, OpDestroy(aHandle));
 }
 
 void
 ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                 TextureClient* aTexture)
 {
   MOZ_ASSERT(CanSend());
   MOZ_ASSERT(aTexture);
   MOZ_ASSERT(aTexture->IsSharedWithCompositor());
   MOZ_ASSERT(aCompositable->IsConnected());
   if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
     return;
   }
 
-  CompositableOperation op(
+  mTxn->AddNoSwapEdit(CompositableOperation(
     aCompositable->GetIPCHandle(),
-    OpRemoveTexture(nullptr, aTexture->GetIPDLActor()));
-
-  if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
-    mTxn->AddEdit(op);
-  } else {
-    mTxn->AddNoSwapEdit(op);
-  }
+    OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
 }
 
 bool ImageBridgeChild::IsSameProcess() const
 {
   return OtherPid() == base::GetCurrentProcId();
 }
 
 bool
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -277,17 +277,17 @@ public:
   /**
    * Notify id of Texture When host side end its use. Transaction id is used to
    * make sure if there is no newer usage.
    */
   void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
 
   virtual void CancelWaitForRecycle(uint64_t aTextureId) override;
 
-  virtual bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
+  virtual bool DestroyInTransaction(PTextureChild* aTexture) override;
   bool DestroyInTransaction(const CompositableHandle& aHandle);
 
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override
   {
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -172,27 +172,16 @@ ImageBridgeParent::RecvUpdate(EditArray&
     // buffers have completed, so that neither process stomps on the
     // other's buffer contents.
     LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
   }
 
   return IPC_OK();
 }
 
-mozilla::ipc::IPCResult
-ImageBridgeParent::RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                                    const uint64_t& aFwdTransactionId)
-{
-  bool success = RecvUpdate(Move(aEdits), Move(aToDestroy), aFwdTransactionId);
-  if (!success) {
-    return IPC_FAIL_NO_REASON(this);
-  }
-  return IPC_OK();
-}
-
 /* static */ bool
 ImageBridgeParent::CreateForContent(Endpoint<PImageBridgeParent>&& aEndpoint)
 {
   MessageLoop* loop = CompositorThreadHolder::Loop();
 
   RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aEndpoint.OtherPid());
   loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeParent>&&>(
     bridge, &ImageBridgeParent::Bind, Move(aEndpoint)));
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -67,18 +67,16 @@ public:
   {
     return OtherPid();
   }
 
   // PImageBridge
   virtual mozilla::ipc::IPCResult RecvImageBridgeThreadId(const PlatformThreadId& aThreadId) override;
   virtual mozilla::ipc::IPCResult RecvUpdate(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
                                           const uint64_t& aFwdTransactionId) override;
-  virtual mozilla::ipc::IPCResult RecvUpdateNoSwap(EditArray&& aEdits, OpDestroyArray&& aToDestroy,
-                                                const uint64_t& aFwdTransactionId) override;
 
   virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData,
                                               const LayersBackend& aLayersBackend,
                                               const TextureFlags& aFlags,
                                               const uint64_t& aSerial) override;
   virtual bool DeallocPTextureParent(PTextureParent* actor) override;
 
   virtual mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -89,22 +89,16 @@ LayerTransactionParent::RecvShutdown()
 
 void
 LayerTransactionParent::Destroy()
 {
   mDestroyed = true;
   mCompositables.clear();
 }
 
-mozilla::ipc::IPCResult
-LayerTransactionParent::RecvUpdateNoSwap(const TransactionInfo& txn)
-{
-  return RecvUpdate(txn);
-}
-
 class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
 {
 public:
   explicit AutoLayerTransactionParentAsyncMessageSender(LayerTransactionParent* aLayerTransaction,
                                                         const InfallibleTArray<OpDestroy>* aDestroyActors = nullptr)
     : mLayerTransaction(aLayerTransaction)
     , mActorsToDestroy(aDestroyActors)
   {
--- a/gfx/layers/ipc/LayerTransactionParent.h
+++ b/gfx/layers/ipc/LayerTransactionParent.h
@@ -108,18 +108,16 @@ public:
 protected:
   virtual mozilla::ipc::IPCResult RecvShutdown() override;
 
   virtual mozilla::ipc::IPCResult RecvPaintTime(const uint64_t& aTransactionId,
                                                 const TimeDuration& aPaintTime) override;
 
   virtual mozilla::ipc::IPCResult RecvUpdate(const TransactionInfo& aInfo) override;
 
-  virtual mozilla::ipc::IPCResult RecvUpdateNoSwap(const TransactionInfo& aInfo) override;
-
   virtual mozilla::ipc::IPCResult RecvSetLayerObserverEpoch(const uint64_t& aLayerObserverEpoch) override;
   virtual mozilla::ipc::IPCResult RecvNewCompositable(const CompositableHandle& aHandle,
                                                       const TextureInfo& aInfo) override;
   virtual mozilla::ipc::IPCResult RecvReleaseLayer(const LayerHandle& aHandle) override;
   virtual mozilla::ipc::IPCResult RecvReleaseCompositable(const CompositableHandle& aHandle) override;
 
   virtual mozilla::ipc::IPCResult RecvClearCachedResources() override;
   virtual mozilla::ipc::IPCResult RecvForceComposite() override;
--- a/gfx/layers/ipc/PImageBridge.ipdl
+++ b/gfx/layers/ipc/PImageBridge.ipdl
@@ -33,19 +33,17 @@ sync protocol PImageBridge
 child:
   async ParentAsyncMessages(AsyncParentMessageData[] aMessages);
 
   async DidComposite(ImageCompositeNotification[] aNotifications);
 
 parent:
   async ImageBridgeThreadId(PlatformThreadId aTreahdId);
 
-  sync Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);
-
-  async UpdateNoSwap(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);
+  async Update(CompositableOperation[] ops, OpDestroy[] toDestroy, uint64_t fwdTransactionId);
 
   // First step of the destruction sequence. This puts ImageBridge
   // in a state in which it can't send asynchronous messages
   // so as to not race with the channel getting closed.
   // In the child side, the Closing the channel does not happen right after WillClose,
   // it is scheduled in the ImageBridgeChild's message queue in order to ensure
   // that all of the messages from the parent side have been received and processed
   // before sending closing the channel.
--- a/gfx/layers/ipc/PLayerTransaction.ipdl
+++ b/gfx/layers/ipc/PLayerTransaction.ipdl
@@ -47,24 +47,20 @@ union MaybeTransform {
  * there is one) or the UI process otherwise.
  */
 sync protocol PLayerTransaction {
   manager PCompositorBridge;
 
 parent:
   // The isFirstPaint flag can be used to indicate that this is the first update
   // for a particular document.
-  sync Update(TransactionInfo txn);
+  async Update(TransactionInfo txn);
 
   async PaintTime(uint64_t id, TimeDuration paintTime);
 
-  // We don't need to send a sync transaction if
-  // no transaction operate require a swap.
-  async UpdateNoSwap(TransactionInfo txn);
-
   async SetLayerObserverEpoch(uint64_t layerObserverEpoch);
 
   // Create a new Compositable.
   async NewCompositable(CompositableHandle handle, TextureInfo info);
 
   // Release an object that is no longer in use.
   async ReleaseLayer(LayerHandle layer);
   async ReleaseCompositable(CompositableHandle compositable);
--- a/gfx/layers/ipc/PTexture.ipdl
+++ b/gfx/layers/ipc/PTexture.ipdl
@@ -29,18 +29,13 @@ child:
     async __delete__();
 
 parent:
     /**
      * Asynchronously tell the compositor side to remove the texture.
      */
     async Destroy();
 
-    /**
-     * Synchronously tell the compositor side to remove the texture.
-     */
-    sync DestroySync();
-
     async RecycleTexture(TextureFlags aTextureFlags);
 };
 
 } // layers
 } // mozilla
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -55,17 +55,16 @@ typedef nsTArray<Edit> EditVector;
 typedef nsTHashtable<nsPtrHashKey<ShadowableLayer>> ShadowableLayerSet;
 typedef nsTArray<OpDestroy> OpDestroyVector;
 
 class Transaction
 {
 public:
   Transaction()
     : mTargetRotation(ROTATION_0)
-    , mSwapRequired(false)
     , mOpen(false)
     , mRotationChanged(false)
   {}
 
   void Begin(const gfx::IntRect& aTargetBounds, ScreenRotation aRotation,
              dom::ScreenOrientationInternal aOrientation)
   {
     mOpen = true;
@@ -75,34 +74,25 @@ public:
       // aRotation is 0, but we should be OK because for the first transaction
       // we should only compose if it is non-empty. See the caller(s) of
       // RotationChanged.
       mRotationChanged = true;
     }
     mTargetRotation = aRotation;
     mTargetOrientation = aOrientation;
   }
-  void MarkSyncTransaction()
-  {
-    mSwapRequired = true;
-  }
   void AddEdit(const Edit& aEdit)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mCset.AppendElement(aEdit);
   }
   void AddEdit(const CompositableOperation& aEdit)
   {
     AddEdit(Edit(aEdit));
   }
-  void AddPaint(const CompositableOperation& aPaint)
-  {
-    AddNoSwapPaint(Edit(aPaint));
-    mSwapRequired = true;
-  }
 
   void AddNoSwapPaint(const CompositableOperation& aPaint)
   {
     MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
     mPaints.AppendElement(Edit(aPaint));
   }
   void AddMutant(ShadowableLayer* aLayer)
   {
@@ -117,17 +107,16 @@ public:
   void End()
   {
     mCset.Clear();
     mPaints.Clear();
     mMutants.Clear();
     mSimpleMutants.Clear();
     mDestroyedActors.Clear();
     mOpen = false;
-    mSwapRequired = false;
     mRotationChanged = false;
   }
 
   bool Empty() const {
     return mCset.IsEmpty() &&
            mPaints.IsEmpty() &&
            mMutants.IsEmpty() &&
            mSimpleMutants.IsEmpty() &&
@@ -143,17 +132,16 @@ public:
   EditVector mCset;
   nsTArray<CompositableOperation> mPaints;
   OpDestroyVector mDestroyedActors;
   ShadowableLayerSet mMutants;
   ShadowableLayerSet mSimpleMutants;
   gfx::IntRect mTargetBounds;
   ScreenRotation mTargetRotation;
   dom::ScreenOrientationInternal mTargetOrientation;
-  bool mSwapRequired;
 
 private:
   bool mOpen;
   bool mRotationChanged;
 
   // disabled
   Transaction(const Transaction&);
   Transaction& operator=(const Transaction&);
@@ -478,40 +466,36 @@ ShadowLayerForwarder::UseComponentAlphaT
         nullptr, aTextureOnBlack->GetIPDLActor(),
         nullptr, aTextureOnWhite->GetIPDLActor(),
         readLockB, readLockW)
       )
     );
 }
 
 static bool
-AddOpDestroy(Transaction* aTxn, const OpDestroy& op, bool synchronously)
+AddOpDestroy(Transaction* aTxn, const OpDestroy& op)
 {
   if (!aTxn->Opened()) {
     return false;
   }
 
   aTxn->mDestroyedActors.AppendElement(op);
-  if (synchronously) {
-    aTxn->MarkSyncTransaction();
-  }
-
   return true;
 }
 
 bool
-ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
+ShadowLayerForwarder::DestroyInTransaction(PTextureChild* aTexture)
 {
-  return AddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
+  return AddOpDestroy(mTxn, OpDestroy(aTexture));
 }
 
 bool
 ShadowLayerForwarder::DestroyInTransaction(const CompositableHandle& aHandle)
 {
-  return AddOpDestroy(mTxn, OpDestroy(aHandle), false);
+  return AddOpDestroy(mTxn, OpDestroy(aHandle));
 }
 
 void
 ShadowLayerForwarder::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
@@ -521,19 +505,16 @@ ShadowLayerForwarder::RemoveTextureFromC
     // We don't have an actor anymore, don't try to use it!
     return;
   }
 
   mTxn->AddEdit(
     CompositableOperation(
       aCompositable->GetIPCHandle(),
       OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
-  if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
-    mTxn->MarkSyncTransaction();
-  }
 }
 
 bool
 ShadowLayerForwarder::InWorkerThread()
 {
   return MessageLoop::current() && (GetTextureForwarder()->GetMessageLoop()->id() == MessageLoop::current()->id());
 }
 
@@ -714,32 +695,21 @@ ShadowLayerForwarder::EndTransaction(con
 
   if (!GetTextureForwarder()->IsSameProcess()) {
     MOZ_LAYERS_LOG(("[LayersForwarder] syncing before send..."));
     PlatformSyncBeforeUpdate();
   }
 
   profiler_tracing("Paint", "Rasterize", TRACING_INTERVAL_END);
 
-  if (mTxn->mSwapRequired) {
-    MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
-    RenderTraceScope rendertrace3("Forward Transaction", "000093");
-    if (!mShadowManager->SendUpdate(info)) {
-      MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
-      return false;
-    }
-  } else {
-    // If we don't require a swap we can call SendUpdateNoSwap which
-    // assumes that aReplies is empty (DEBUG assertion)
-    MOZ_LAYERS_LOG(("[LayersForwarder] sending no swap transaction..."));
-    RenderTraceScope rendertrace3("Forward NoSwap Transaction", "000093");
-    if (!mShadowManager->SendUpdateNoSwap(info)) {
-      MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
-      return false;
-    }
+  MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
+  RenderTraceScope rendertrace3("Forward Transaction", "000093");
+  if (!mShadowManager->SendUpdate(info)) {
+    MOZ_LAYERS_LOG(("[LayersForwarder] WARNING: sending transaction failed!"));
+    return false;
   }
 
   *aSent = true;
   mIsFirstPaint = false;
   mPaintSyncId = 0;
   MOZ_LAYERS_LOG(("[LayersForwarder] ... done"));
   return true;
 }
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -247,17 +247,17 @@ public:
 
   /**
    * See CompositableForwarder::UseTiledLayerBuffer
    */
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                                    const SurfaceDescriptorTiles& aTileLayerDescriptor) override;
 
   void ReleaseCompositable(const CompositableHandle& aHandle) override;
-  bool DestroyInTransaction(PTextureChild* aTexture, bool synchronously) override;
+  bool DestroyInTransaction(PTextureChild* aTexture) override;
   bool DestroyInTransaction(const CompositableHandle& aHandle);
 
   virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                              TextureClient* aTexture) override;
 
   /**
    * Communicate to the compositor that aRegion in the texture identified by aLayer
    * and aIdentifier has been updated to aThebesBuffer.
--- a/gfx/layers/wr/WebRenderBridgeChild.cpp
+++ b/gfx/layers/wr/WebRenderBridgeChild.cpp
@@ -12,17 +12,16 @@
 #include "mozilla/layers/ImageDataSerializer.h"
 #include "mozilla/layers/PTextureChild.h"
 
 namespace mozilla {
 namespace layers {
 
 WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
   : mIsInTransaction(false)
-  , mSyncTransaction(false)
   , mIPCOpen(false)
   , mDestroyed(false)
 {
 }
 
 void
 WebRenderBridgeChild::Destroy()
 {
@@ -74,17 +73,16 @@ WebRenderBridgeChild::DPEnd(bool aIsSync
     this->SendDPSyncEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
   } else {
     this->SendDPEnd(mCommands, mDestroyedActors, GetFwdTransactionId(), aTransactionId);
   }
 
   mCommands.Clear();
   mDestroyedActors.Clear();
   mIsInTransaction = false;
-  mSyncTransaction = false;
 }
 
 uint64_t
 WebRenderBridgeChild::GetNextExternalImageId()
 {
   static uint32_t sNextID = 1;
   ++sNextID;
   MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
@@ -171,48 +169,45 @@ void
 WebRenderBridgeChild::UpdateTextureRegion(CompositableClient* aCompositable,
                                           const ThebesBufferData& aThebesBufferData,
                                           const nsIntRegion& aUpdatedRegion)
 {
 
 }
 
 bool
-WebRenderBridgeChild::AddOpDestroy(const OpDestroy& aOp, bool aSynchronously)
+WebRenderBridgeChild::AddOpDestroy(const OpDestroy& aOp)
 {
   if (!mIsInTransaction) {
     return false;
   }
 
   mDestroyedActors.AppendElement(aOp);
-  if (aSynchronously) {
-    MarkSyncTransaction();
-  }
   return true;
 }
 
 void
 WebRenderBridgeChild::ReleaseCompositable(const CompositableHandle& aHandle)
 {
   if (!DestroyInTransaction(aHandle)) {
     SendReleaseCompositable(aHandle);
   }
   mCompositables.Remove(aHandle.Value());
 }
 
 bool
-WebRenderBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool aSynchronously)
+WebRenderBridgeChild::DestroyInTransaction(PTextureChild* aTexture)
 {
-  return AddOpDestroy(OpDestroy(aTexture), aSynchronously);
+  return AddOpDestroy(OpDestroy(aTexture));
 }
 
 bool
 WebRenderBridgeChild::DestroyInTransaction(const CompositableHandle& aHandle)
 {
-  return AddOpDestroy(OpDestroy(aHandle), false);
+  return AddOpDestroy(OpDestroy(aHandle));
 }
 
 void
 WebRenderBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                                     TextureClient* aTexture)
 {
   MOZ_ASSERT(aCompositable);
   MOZ_ASSERT(aTexture);
@@ -222,19 +217,16 @@ WebRenderBridgeChild::RemoveTextureFromC
     // We don't have an actor anymore, don't try to use it!
     return;
   }
 
   AddWebRenderCommand(
     CompositableOperation(
       aCompositable->GetIPCHandle(),
       OpRemoveTexture(nullptr, aTexture->GetIPDLActor())));
-  if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
-    MarkSyncTransaction();
-  }
 }
 
 void
 WebRenderBridgeChild::UseTextures(CompositableClient* aCompositable,
                                   const nsTArray<TimedTextureClient>& aTextures)
 {
   MOZ_ASSERT(aCompositable);
 
@@ -249,25 +241,16 @@ WebRenderBridgeChild::UseTextures(Compos
     MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
     MOZ_RELEASE_ASSERT(t.mTextureClient->GetIPDLActor()->GetIPCChannel() == GetIPCChannel());
     ReadLockDescriptor readLock;
     t.mTextureClient->SerializeReadLock(readLock);
     textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
                                         readLock,
                                         t.mTimeStamp, t.mPictureRect,
                                         t.mFrameID, t.mProducerID));
-    if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD)
-        && t.mTextureClient->HasIntermediateBuffer()) {
-
-      // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
-      // race with updates on the main thread. In this case we want the transaction
-      // to be synchronous.
-
-      MarkSyncTransaction();
-    }
     GetCompositorBridgeChild()->HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
   }
   AddWebRenderCommand(CompositableOperation(aCompositable->GetIPCHandle(),
                                             OpUseTexture(textures)));
 }
 
 void
 WebRenderBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
--- a/gfx/layers/wr/WebRenderBridgeChild.h
+++ b/gfx/layers/wr/WebRenderBridgeChild.h
@@ -48,38 +48,33 @@ public:
   /**
    * Clean this up, finishing with SendShutDown() which will cause __delete__
    * to be sent from the parent side.
    */
   void Destroy();
   bool IPCOpen() const { return mIPCOpen && !mDestroyed; }
   bool IsDestroyed() const { return mDestroyed; }
 
-  void MarkSyncTransaction()
-  {
-    mSyncTransaction = true;
-  }
-
 private:
   friend class CompositorBridgeChild;
 
   ~WebRenderBridgeChild() {}
 
   uint64_t GetNextExternalImageId();
 
   // CompositableForwarder
   void Connect(CompositableClient* aCompositable,
                ImageContainer* aImageContainer = nullptr) override;
   void UseTiledLayerBuffer(CompositableClient* aCompositable,
                            const SurfaceDescriptorTiles& aTiledDescriptor) override;
   void UpdateTextureRegion(CompositableClient* aCompositable,
                            const ThebesBufferData& aThebesBufferData,
                            const nsIntRegion& aUpdatedRegion) override;
   void ReleaseCompositable(const CompositableHandle& aHandle) override;
-  bool DestroyInTransaction(PTextureChild* aTexture, bool aSynchronously) override;
+  bool DestroyInTransaction(PTextureChild* aTexture) override;
   bool DestroyInTransaction(const CompositableHandle& aHandle);
   void RemoveTextureFromCompositable(CompositableClient* aCompositable,
                                      TextureClient* aTexture) override;
   void UseTextures(CompositableClient* aCompositable,
                    const nsTArray<TimedTextureClient>& aTextures) override;
   void UseComponentAlphaTextures(CompositableClient* aCompositable,
                                  TextureClient* aClientOnBlack,
                                  TextureClient* aClientOnWhite) override;
@@ -95,23 +90,22 @@ private:
     AddRef();
   }
   void ReleaseIPDLReference() {
     MOZ_ASSERT(mIPCOpen == true);
     mIPCOpen = false;
     Release();
   }
 
-  bool AddOpDestroy(const OpDestroy& aOp, bool aSynchronously);
+  bool AddOpDestroy(const OpDestroy& aOp);
 
   nsTArray<WebRenderCommand> mCommands;
   nsTArray<OpDestroy> mDestroyedActors;
   nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
   bool mIsInTransaction;
-  bool mSyncTransaction;
 
   bool mIPCOpen;
   bool mDestroyed;
 };
 
 } // namespace layers
 } // namespace mozilla
 
--- a/gfx/layers/wr/WebRenderCompositorOGL.cpp
+++ b/gfx/layers/wr/WebRenderCompositorOGL.cpp
@@ -101,28 +101,16 @@ WebRenderCompositorOGL::MakeCurrent(Make
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
   mGLContext->MakeCurrent(aFlags & ForceMakeCurrent);
 }
 
 void
-WebRenderCompositorOGL::CompositeUntil(TimeStamp aTimeStamp)
-{
-  Compositor::CompositeUntil(aTimeStamp);
-  // We're not really taking advantage of the stored composite-again-time here.
-  // We might be able to skip the next few composites altogether. However,
-  // that's a bit complex to implement and we'll get most of the advantage
-  // by skipping compositing when we detect there's nothing invalid. This is why
-  // we do "composite until" rather than "composite again at".
-  ScheduleComposition();
-}
-
-void
 WebRenderCompositorOGL::AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost)
 {
   MOZ_ASSERT(!mCompositableHosts.Get(aExternalImageId));
   mCompositableHosts.Put(aExternalImageId, aHost);
 }
 
 void
 WebRenderCompositorOGL::RemoveExternalImageId(uint64_t aExternalImageId)
--- a/gfx/layers/wr/WebRenderCompositorOGL.h
+++ b/gfx/layers/wr/WebRenderCompositorOGL.h
@@ -107,18 +107,16 @@ public:
 #endif // MOZ_DUMP_PAINTING
 
   virtual LayersBackend GetBackendType() const override {
     return LayersBackend::LAYERS_WR;
   }
 
   virtual bool IsValid() const override { return true; }
 
-  virtual void CompositeUntil(TimeStamp aTimeStamp) override;
-
   GLContext* gl() const { return mGLContext; }
 
   void AddExternalImageId(uint64_t aExternalImageId, CompositableHost* aHost);
   void RemoveExternalImageId(uint64_t aExternalImageId);
   void UpdateExternalImages();
 
   void ScheduleComposition();
 private:
--- a/image/DecodePool.cpp
+++ b/image/DecodePool.cpp
@@ -60,17 +60,18 @@ public:
     , mShuttingDown(false)
   { }
 
   /// Shut down the provided decode pool thread.
   static void ShutdownThread(nsIThread* aThisThread)
   {
     // Threads have to be shut down from another thread, so we'll ask the
     // main thread to do it for us.
-    NS_DispatchToMainThread(NewRunnableMethod(aThisThread, &nsIThread::Shutdown));
+    NS_DispatchToMainThread(NewRunnableMethod("DecodePoolImpl::ShutdownThread",
+                                              aThisThread, &nsIThread::Shutdown));
   }
 
   /**
    * Requests shutdown. New work items will be dropped on the floor, and all
    * decode pool threads will be shut down once existing work items have been
    * processed.
    */
   void RequestShutdown()
--- a/image/IDecodingTask.cpp
+++ b/image/IDecodingTask.cpp
@@ -45,17 +45,19 @@ IDecodingTask::NotifyProgress(NotNull<Ra
   if (NS_IsMainThread() && !(decoderFlags & DecoderFlags::ASYNC_NOTIFY)) {
     aImage->NotifyProgress(progress, invalidRect, frameCount,
                            decoderFlags, surfaceFlags);
     return;
   }
 
   // We're forced to notify asynchronously.
   NotNull<RefPtr<RasterImage>> image = aImage;
-  NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
+  NS_DispatchToMainThread(NS_NewRunnableFunction(
+                            "IDecodingTask::NotifyProgress",
+                            [=]() -> void {
     image->NotifyProgress(progress, invalidRect, frameCount,
                           decoderFlags, surfaceFlags);
   }));
 }
 
 /* static */ void
 IDecodingTask::NotifyDecodeComplete(NotNull<RasterImage*> aImage,
                                     NotNull<Decoder*> aDecoder)
@@ -78,17 +80,19 @@ IDecodingTask::NotifyDecodeComplete(NotN
     aImage->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
                                  invalidRect, frameCount, decoderFlags,
                                  surfaceFlags);
     return;
   }
 
   // We're forced to notify asynchronously.
   NotNull<RefPtr<RasterImage>> image = aImage;
-  NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
+  NS_DispatchToMainThread(NS_NewRunnableFunction(
+                            "IDecodingTask::NotifyDecodeComplete",
+                            [=]() -> void {
     image->NotifyDecodeComplete(finalStatus, metadata, telemetry, progress,
                                 invalidRect, frameCount, decoderFlags,
                                 surfaceFlags);
   }));
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
--- a/image/ProgressTracker.cpp
+++ b/image/ProgressTracker.cpp
@@ -118,17 +118,18 @@ ProgressTracker::GetImageStatus() const
 }
 
 // A helper class to allow us to call SyncNotify asynchronously.
 class AsyncNotifyRunnable : public Runnable
 {
   public:
     AsyncNotifyRunnable(ProgressTracker* aTracker,
                         IProgressObserver* aObserver)
-      : mTracker(aTracker)
+     : Runnable("ProgressTracker::AsyncNotifyRunnable")
+     , mTracker(aTracker)
     {
       MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
       MOZ_ASSERT(aTracker, "aTracker should not be null");
       MOZ_ASSERT(aObserver, "aObserver should not be null");
       mObservers.AppendElement(aObserver);
     }
 
     NS_IMETHOD Run() override
--- a/image/RasterImage.cpp
+++ b/image/RasterImage.cpp
@@ -419,17 +419,18 @@ RasterImage::WillDrawOpaqueNow()
   return true;
 }
 
 void
 RasterImage::OnSurfaceDiscarded()
 {
   MOZ_ASSERT(mProgressTracker);
 
-  NS_DispatchToMainThread(NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard));
+  NS_DispatchToMainThread(NewRunnableMethod("ProgressTracker::OnDiscard",
+                                            mProgressTracker, &ProgressTracker::OnDiscard));
 }
 
 //******************************************************************************
 NS_IMETHODIMP
 RasterImage::GetAnimated(bool* aAnimated)
 {
   if (mError) {
     return NS_ERROR_FAILURE;
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -994,17 +994,19 @@ VectorImage::CreateSurfaceAndShow(const 
 
   // Send out an invalidation so that surfaces that are still in use get
   // re-locked. See the discussion of the UnlockSurfaces call above.
   if (!(aParams.flags & FLAG_ASYNC_NOTIFY)) {
     mProgressTracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE,
                                          GetMaxSizedIntRect());
   } else {
     NotNull<RefPtr<VectorImage>> image = WrapNotNull(this);
-    NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
+    NS_DispatchToMainThread(NS_NewRunnableFunction(
+                              "ProgressTracker::SyncNotifyProgress",
+                              [=]() -> void {
       RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
       if (tracker) {
         tracker->SyncNotifyProgress(FLAG_FRAME_COMPLETE,
                                     GetMaxSizedIntRect());
       }
     }));
   }
 }
--- a/image/imgRequestProxy.cpp
+++ b/image/imgRequestProxy.cpp
@@ -344,17 +344,18 @@ imgRequestProxy::CancelAndForgetObserver
 
   if (GetOwner()) {
     GetOwner()->RemoveProxy(this, aStatus);
   }
 
   mIsInLoadGroup = oldIsInLoadGroup;
 
   if (mIsInLoadGroup) {
-    NS_DispatchToCurrentThread(NewRunnableMethod(this, &imgRequestProxy::DoRemoveFromLoadGroup));
+    NS_DispatchToCurrentThread(NewRunnableMethod("imgRequestProxy::DoRemoveFromLoadGroup",
+                                                 this, &imgRequestProxy::DoRemoveFromLoadGroup));
   }
 
   NullOutListener();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/image/imgRequestProxy.h
+++ b/image/imgRequestProxy.h
@@ -137,17 +137,17 @@ protected:
 
   class imgCancelRunnable;
   friend class imgCancelRunnable;
 
   class imgCancelRunnable : public mozilla::Runnable
   {
     public:
       imgCancelRunnable(imgRequestProxy* owner, nsresult status)
-        : mOwner(owner), mStatus(status)
+        : Runnable("imgCancelRunnable"), mOwner(owner), mStatus(status)
       { }
 
       NS_IMETHOD Run() override {
         mOwner->DoCancel(mStatus);
         return NS_OK;
       }
 
     private:
--- a/ipc/glue/CrashReporterClient.cpp
+++ b/ipc/glue/CrashReporterClient.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 "CrashReporterClient.h"
 #include "CrashReporterMetadataShmem.h"
 #include "nsISupportsImpl.h"
 
+#ifdef MOZ_CRASHREPORTER
 namespace mozilla {
 namespace ipc {
 
 StaticMutex CrashReporterClient::sLock;
 StaticRefPtr<CrashReporterClient> CrashReporterClient::sClientSingleton;
 
 CrashReporterClient::CrashReporterClient(const Shmem& aShmem)
  : mMetadata(new CrashReporterMetadataShmem(aShmem))
@@ -59,8 +60,9 @@ CrashReporterClient::DestroySingleton()
 CrashReporterClient::GetSingleton()
 {
   StaticMutexAutoLock lock(sLock);
   return sClientSingleton;
 }
 
 } // namespace ipc
 } // namespace mozilla
+#endif // MOZ_CRASHREPORTER
--- a/ipc/glue/CrashReporterClient.h
+++ b/ipc/glue/CrashReporterClient.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_ipc_CrashReporterClient_h
 #define mozilla_ipc_CrashReporterClient_h
 
 #include "mozilla/StaticMutex.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/Unused.h"
 #include "mozilla/ipc/Shmem.h"
 
+#ifdef MOZ_CRASHREPORTER
 namespace mozilla {
 namespace ipc {
 
 class CrashReporterMetadataShmem;
 
 class CrashReporterClient
 {
 public:
@@ -27,50 +28,57 @@ public:
   //
   //   async SetCrashReporterClient(Shmem shmem);
   //
   // The parent-side receive function of this message should save the shmem
   // somewhere, and when the top-level actor's ActorDestroy runs (or when the
   // crash reporter needs metadata), the shmem should be parsed.
   template <typename T>
   static bool InitSingleton(T* aToplevelProtocol) {
-    // 16KB should be enough for most metadata - see bug 1278717 comment #11.
-    static const size_t kShmemSize = 16 * 1024;
-
     Shmem shmem;
-    bool rv = aToplevelProtocol->AllocUnsafeShmem(
-      kShmemSize,
-      SharedMemory::TYPE_BASIC,
-      &shmem);
-    if (!rv) {
+    if (!AllocShmem(aToplevelProtocol, &shmem)) {
       return false;
     }
 
     InitSingletonWithShmem(shmem);
-    Unused << aToplevelProtocol->SendInitCrashReporter(shmem);
+    Unused << aToplevelProtocol->SendInitCrashReporter(
+      shmem,
+      CrashReporter::CurrentThreadId());
     return true;
   }
 
+  template <typename T>
+  static bool AllocShmem(T* aToplevelProtocol, Shmem* aOutShmem) {
+    // 16KB should be enough for most metadata - see bug 1278717 comment #11.
+    static const size_t kShmemSize = 16 * 1024;
+
+    return aToplevelProtocol->AllocUnsafeShmem(
+      kShmemSize,
+      SharedMemory::TYPE_BASIC,
+      aOutShmem);
+  }
+
+  static void InitSingletonWithShmem(const Shmem& aShmem);
+
   static void DestroySingleton();
   static RefPtr<CrashReporterClient> GetSingleton();
 
   void AnnotateCrashReport(const nsCString& aKey, const nsCString& aData);
   void AppendAppNotes(const nsCString& aData);
 
 private:
   explicit CrashReporterClient(const Shmem& aShmem);
   ~CrashReporterClient();
 
-  static void InitSingletonWithShmem(const Shmem& aShmem);
-
 private:
   static StaticMutex sLock;
   static StaticRefPtr<CrashReporterClient> sClientSingleton;
 
 private:
   UniquePtr<CrashReporterMetadataShmem> mMetadata;
 };
 
 } // namespace ipc
 } // namespace mozilla
+#endif // MOZ_CRASHREPORTER
 
 #endif // mozilla_ipc_CrashReporterClient_h
 
--- a/ipc/glue/CrashReporterHost.cpp
+++ b/ipc/glue/CrashReporterHost.cpp
@@ -13,33 +13,63 @@
 #ifdef MOZ_CRASHREPORTER
 # include "nsIAsyncShutdown.h"
 # include "nsICrashService.h"
 #endif
 
 namespace mozilla {
 namespace ipc {
 
-CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType, const Shmem& aShmem)
+CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
+                                     const Shmem& aShmem,
+                                     CrashReporter::ThreadId aThreadId)
  : mProcessType(aProcessType),
    mShmem(aShmem),
-   mStartTime(::time(nullptr))
+   mThreadId(aThreadId),
+   mStartTime(::time(nullptr)),
+   mFinalized(false)
 {
 }
 
 #ifdef MOZ_CRASHREPORTER
 bool
-CrashReporterHost::GenerateCrashReport(RefPtr<nsIFile> aCrashDump,
-                                       const AnnotationTable* aExtraNotes,
-                                       nsString* aOutMinidumpID)
+CrashReporterHost::GenerateCrashReport(base::ProcessId aPid)
 {
-  nsString dumpID;
-  if (!CrashReporter::GetIDFromMinidump(aCrashDump, dumpID)) {
+  if (!TakeCrashedChildMinidump(aPid, nullptr)) {
     return false;
   }
+  return FinalizeCrashReport();
+}
+
+RefPtr<nsIFile>
+CrashReporterHost::TakeCrashedChildMinidump(base::ProcessId aPid, uint32_t* aOutSequence)
+{
+  MOZ_ASSERT(!HasMinidump());
+
+  RefPtr<nsIFile> crashDump;
+  if (!XRE_TakeMinidumpForChild(aPid, getter_AddRefs(crashDump), aOutSequence)) {
+    return nullptr;
+  }
+  if (!AdoptMinidump(crashDump)) {
+    return nullptr;
+  }
+  return crashDump.get();
+}
+
+bool
+CrashReporterHost::AdoptMinidump(nsIFile* aFile)
+{
+  return CrashReporter::GetIDFromMinidump(aFile, mDumpID);
+}
+
+bool
+CrashReporterHost::FinalizeCrashReport()
+{
+  MOZ_ASSERT(!mFinalized);
+  MOZ_ASSERT(HasMinidump());
 
   CrashReporter::AnnotationTable notes;
 
   nsAutoCString type;
   switch (mProcessType) {
     case GeckoProcessType_Content:
       type = NS_LITERAL_CSTRING("content");
       break;
@@ -55,25 +85,28 @@ CrashReporterHost::GenerateCrashReport(R
       break;
   }
   notes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
 
   char startTime[32];
   SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
   notes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
 
-  CrashReporterMetadataShmem::ReadAppNotes(mShmem, &notes);
-  if (aExtraNotes) {
-    CrashReporter::AppendExtraData(dumpID, *aExtraNotes);
+  // We might not have shmem (for example, when running crashreporter tests).
+  if (mShmem.IsReadable()) {
+    CrashReporterMetadataShmem::ReadAppNotes(mShmem, &notes);
   }
-  CrashReporter::AppendExtraData(dumpID, notes);
+  CrashReporter::AppendExtraData(mDumpID, mExtraNotes);
+  CrashReporter::AppendExtraData(mDumpID, notes);
 
-  NotifyCrashService(mProcessType, dumpID, &notes);
+  // Use mExtraNotes, since NotifyCrashService looks for "PluginHang" which is
+  // set in the parent process.
+  NotifyCrashService(mProcessType, mDumpID, &mExtraNotes);
 
-  *aOutMinidumpID = dumpID;
+  mFinalized = true;
   return true;
 }
 
 /**
  * Runnable used to execute the minidump analyzer program asynchronously after
  * a crash. This should run on a background thread not to block the main thread
  * over the potentially long minidump analysis. Once analysis is over, the
  * crash information will be relayed to the crash manager via another runnable
@@ -264,12 +297,18 @@ CrashReporterHost::NotifyCrashService(Ge
     default:
       NS_ERROR("unknown process type");
       return;
   }
 
   AsyncAddCrash(processType, crashType, aChildDumpID);
   Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1);
 }
+
+void
+CrashReporterHost::AddNote(const nsCString& aKey, const nsCString& aValue)
+{
+  mExtraNotes.Put(aKey, aValue);
+}
 #endif
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/CrashReporterHost.h
+++ b/ipc/glue/CrashReporterHost.h
@@ -21,50 +21,104 @@ namespace ipc {
 // terminates abnormally, the top-level should call GenerateCrashReport to
 // automatically integrate metadata.
 class CrashReporterHost
 {
   typedef mozilla::ipc::Shmem Shmem;
   typedef CrashReporter::AnnotationTable AnnotationTable;
 
 public:
-  CrashReporterHost(GeckoProcessType aProcessType, const Shmem& aShmem);
+  CrashReporterHost(GeckoProcessType aProcessType,
+                    const Shmem& aShmem,
+                    CrashReporter::ThreadId aThreadId);
 
 #ifdef MOZ_CRASHREPORTER
-  bool GenerateCrashReport(base::ProcessId aPid,
-                           const AnnotationTable* aExtraNotes = nullptr,
-                           nsString* aOutMinidumpID = nullptr)
+  // Helper function for generating a crash report for a process that probably
+  // crashed (i.e., had an AbnormalShutdown in ActorDestroy). Returns true if
+  // the process has a minidump attached and we were able to generate a report.
+  bool GenerateCrashReport(base::ProcessId aPid);
+
+  // Given an existing minidump for a crashed child process, take ownership of
+  // it from IPDL. After this, FinalizeCrashReport may be called.
+  RefPtr<nsIFile> TakeCrashedChildMinidump(base::ProcessId aPid, uint32_t* aOutSequence);
+
+  // Replace the stored minidump with a new one. After this,
+  // FinalizeCrashReport may be called.
+  bool AdoptMinidump(nsIFile* aFile);
+
+  // If a minidump was already captured (e.g. via the hang reporter), this
+  // finalizes the existing report by attaching metadata and notifying the
+  // crash service.
+  bool FinalizeCrashReport();
+
+  // Generate a paired minidump. This does not take the crash report, as
+  // GenerateCrashReport does. After this, FinalizeCrashReport may be called.
+  //
+  // This calls TakeCrashedChildMinidump and FinalizeCrashReport.
+  template <typename Toplevel>
+  bool GenerateMinidumpAndPair(Toplevel* aToplevelProtocol,
+                               nsIFile* aMinidumpToPair,
+                               const nsACString& aPairName)
   {
-    RefPtr<nsIFile> crashDump;
-    if (!XRE_TakeMinidumpForChild(aPid, getter_AddRefs(crashDump), nullptr)) {
+    ScopedProcessHandle childHandle;
+#ifdef XP_MACOSX
+    childHandle = aToplevelProtocol->Process()->GetChildTask();
+#else
+    if (!base::OpenPrivilegedProcessHandle(aToplevelProtocol->OtherPid(),
+                                           &childHandle.rwget()))
+    {
+      NS_WARNING("Failed to open child process handle.");
       return false;
     }
-    return GenerateCrashReport(crashDump, aExtraNotes, aOutMinidumpID);
+#endif
+
+    nsCOMPtr<nsIFile> targetDump;
+    if (!CrashReporter::CreateMinidumpsAndPair(childHandle,
+                                               mThreadId,
+                                               aPairName,
+                                               aMinidumpToPair,
+                                               getter_AddRefs(targetDump)))
+    {
+      return false;
+    }
+
+    return CrashReporter::GetIDFromMinidump(targetDump, mDumpID);
   }
 
   // This is a static helper function to notify the crash service that a
   // crash has occurred. When PCrashReporter is removed, we can make this
   // a member function. This can be called from any thread, and if not
   // called from the main thread, will post a synchronous message to the
   // main thread.
   static void NotifyCrashService(
     GeckoProcessType aProcessType,
     const nsString& aChildDumpID,
     const AnnotationTable* aNotes);
+
+  void AddNote(const nsCString& aKey, const nsCString& aValue);
+
+  bool HasMinidump() const {
+    return !mDumpID.IsEmpty();
+  }
+  const nsString& MinidumpID() const {
+    MOZ_ASSERT(HasMinidump());
+    return mDumpID;
+  }
 #endif
 
 private:
-  bool GenerateCrashReport(RefPtr<nsIFile> aCrashDump,
-                           const AnnotationTable* aExtraNotes,
-                           nsString* aOutMinidumpID);
   static void AsyncAddCrash(int32_t aProcessType, int32_t aCrashType,
                             const nsString& aChildDumpID);
 
 private:
   GeckoProcessType mProcessType;
   Shmem mShmem;
+  CrashReporter::ThreadId mThreadId;
   time_t mStartTime;
+  AnnotationTable mExtraNotes;
+  nsString mDumpID;
+  bool mFinalized;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_CrashReporterHost_h
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -176,16 +176,17 @@ static_assert(LastMsgIndex <= 65536, "ne
 #endif // ifndef IPCMessageStart_h
 """
 
 ipc_msgtype_name = StringIO()
 print >>ipc_msgtype_name, """
 // CODE GENERATED by ipdl.py. Do not edit.
 #include <cstdint>
 
+#include "mozilla/ipc/ProtocolUtils.h"
 #include "IPCMessageStart.h"
 
 using std::uint32_t;
 
 namespace {
 
 enum IPCMessages {
 """
@@ -214,16 +215,26 @@ for protocol in sorted(allmessages.keys(
     for (msg, num) in allmessages[protocol].idnums:
         if num or msg.endswith('End'):
             continue
         print >>ipc_msgtype_name, """
   case %s__%s:
     return "%s::%s";""" % (protocol, msg, protocol, msg)
 
 print >>ipc_msgtype_name, """
+  case CHANNEL_OPENED_MESSAGE_TYPE:
+    return "CHANNEL_OPENED_MESSAGE";
+  case SHMEM_DESTROYED_MESSAGE_TYPE:
+    return "SHMEM_DESTROYED_MESSAGE";
+  case SHMEM_CREATED_MESSAGE_TYPE:
+    return "SHMEM_CREATED_MESSAGE";
+  case GOODBYE_MESSAGE_TYPE:
+    return "GOODBYE_MESSAGE";
+  case CANCEL_MESSAGE_TYPE:
+    return "CANCEL_MESSAGE";
   default:
     return "<unknown IPC msg name>";
   }
 }
 
 } // namespace ipc
 } // namespace mozilla
 """
--- a/js/src/builtin/DataViewObject.cpp
+++ b/js/src/builtin/DataViewObject.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "builtin/DataViewObject.h"
 
 #include "mozilla/Alignment.h"
+#include "mozilla/Casting.h"
 
 #include <string.h>
 
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsobj.h"
@@ -31,16 +32,17 @@
 #include "gc/Nursery-inl.h"
 #include "gc/StoreBuffer-inl.h"
 #include "vm/ArrayBufferObject-inl.h"
 #include "vm/NativeObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
+using mozilla::AssertedCast;
 using JS::CanonicalizeNaN;
 using JS::ToInt32;
 using JS::ToUint32;
 
 static NewObjectKind
 DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto)
 {
     if (!proto && byteLength >= TypedArrayObject::SINGLETON_BYTE_LENGTH)
@@ -134,81 +136,73 @@ DataViewObject::create(JSContext* cx, ui
     if (arrayBuffer->is<ArrayBufferObject>()) {
         if (!arrayBuffer->as<ArrayBufferObject>().addView(cx, &dvobj))
             return nullptr;
     }
 
     return &dvobj;
 }
 
+// ES2017 draft rev 931261ecef9b047b14daacf82884134da48dfe0f
+// 24.3.2.1 DataView (extracted part of the main algorithm)
 bool
 DataViewObject::getAndCheckConstructorArgs(JSContext* cx, HandleObject bufobj, const CallArgs& args,
                                            uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr)
 {
+    // Step 3.
     if (!IsArrayBufferMaybeShared(bufobj)) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE,
                                   "DataView", "ArrayBuffer", bufobj->getClass()->name);
         return false;
     }
-
     Rooted<ArrayBufferObjectMaybeShared*> buffer(cx, &AsArrayBufferMaybeShared(bufobj));
-    uint32_t byteOffset = 0;
-    uint32_t byteLength = buffer->byteLength();
 
-    if (args.length() > 1) {
-        if (!ToUint32(cx, args[1], &byteOffset))
-            return false;
-        if (byteOffset > INT32_MAX) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
-                                      "1");
-            return false;
-        }
-    }
+    // Step 4.
+    uint64_t offset;
+    if (!ToIndex(cx, args.get(1), &offset))
+        return false;
 
+    // Step 5.
     if (buffer->isDetached()) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
         return false;
     }
 
-    if (args.length() > 1) {
-        if (byteOffset > byteLength) {
-            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
-                                      "1");
+    // Step 6.
+    uint32_t bufferByteLength = buffer->byteLength();
+
+    // Step 7.
+    if (offset > bufferByteLength) {
+        JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
+        return false;
+    }
+    MOZ_ASSERT(offset <= INT32_MAX);
+
+    // Step 8.a
+    uint64_t viewByteLength = bufferByteLength - offset;
+    if (args.hasDefined(2)) {
+        // Step 9.a.
+        if (!ToIndex(cx, args.get(2), &viewByteLength))
+            return false;
+
+
+        MOZ_ASSERT(offset + viewByteLength >= offset,
+                   "can't overflow: both numbers are less than DOUBLE_INTEGRAL_PRECISION_LIMIT");
+
+        // Step 9.b.
+        if (offset + viewByteLength > bufferByteLength) {
+            JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
+                                      JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
             return false;
         }
-
-        if (args.get(2).isUndefined()) {
-            byteLength -= byteOffset;
-        } else {
-            if (!ToUint32(cx, args[2], &byteLength))
-                return false;
-            if (byteLength > INT32_MAX) {
-                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                                          JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
-                return false;
-            }
+    }
+    MOZ_ASSERT(viewByteLength <= INT32_MAX);
 
-            MOZ_ASSERT(byteOffset + byteLength >= byteOffset,
-                       "can't overflow: both numbers are less than INT32_MAX");
-            if (byteOffset + byteLength > buffer->byteLength()) {
-                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
-                                          JSMSG_ARG_INDEX_OUT_OF_RANGE, "1");
-                return false;
-            }
-        }
-    }
-
-    /* The sum of these cannot overflow a uint32_t */
-    MOZ_ASSERT(byteOffset <= INT32_MAX);
-    MOZ_ASSERT(byteLength <= INT32_MAX);
-
-
-    *byteOffsetPtr = byteOffset;
-    *byteLengthPtr = byteLength;
-
+    *byteOffsetPtr = AssertedCast<uint32_t>(offset);
+    *byteLengthPtr = AssertedCast<uint32_t>(viewByteLength);
     return true;
 }
 
 bool
 DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args)
 {
     MOZ_ASSERT(args.isConstructing());
     assertSameCompartment(cx, bufobj);
--- a/js/src/tests/jstests.list
+++ b/js/src/tests/jstests.list
@@ -411,23 +411,16 @@ skip script test262/built-ins/RegExp/pro
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317395
 skip script test262/built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317394
 skip script test262/built-ins/DataView/prototype/byteOffset/detached-buffer.js
 skip script test262/built-ins/DataView/prototype/byteLength/detached-buffer.js
 
-# https://bugzilla.mozilla.org/show_bug.cgi?id=1317382
-skip script test262/built-ins/DataView/byteoffset-is-negative-throws.js
-skip script test262/built-ins/DataView/excessive-byteoffset-throws.js
-skip script test262/built-ins/DataView/excessive-bytelength-throws.js
-skip script test262/built-ins/DataView/negative-byteoffset-throws.js
-skip script test262/built-ins/DataView/negative-bytelength-throws.js
-
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1317391
 skip script test262/language/statements/class/subclass/class-definition-null-proto-missing-return-override.js
 skip script test262/language/statements/class/subclass/class-definition-null-proto-this.js
 
 # https://bugzilla.mozilla.org/show_bug.cgi?id=1108941
 skip script test262/language/expressions/tagged-template/cache-differing-expressions.js
 skip script test262/language/expressions/tagged-template/cache-differing-expressions-eval.js
 skip script test262/language/expressions/tagged-template/cache-differing-expressions-new-function.js
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -425,16 +425,31 @@ ArgumentsObject::obj_delProperty(JSConte
     } else if (JSID_IS_ATOM(id, cx->names().callee)) {
         argsobj.as<MappedArgumentsObject>().markCalleeOverridden();
     } else if (JSID_IS_SYMBOL(id) && JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().iterator) {
         argsobj.markIteratorOverridden();
     }
     return result.succeed();
 }
 
+/* static */ bool
+ArgumentsObject::obj_mayResolve(const JSAtomState& names, jsid id, JSObject*)
+{
+    // Arguments might resolve indexes or Symbol.iterator.
+    if (!JSID_IS_ATOM(id))
+        return true;
+
+    JSAtom* atom = JSID_TO_ATOM(id);
+    uint32_t index;
+    if (atom->isIndex(&index))
+        return true;
+
+    return atom == names.length || atom == names.callee;
+}
+
 static bool
 MappedArgGetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
     MappedArgumentsObject& argsobj = obj->as<MappedArgumentsObject>();
     if (JSID_IS_INT(id)) {
         /*
          * arg can exceed the number of arguments if a script changed the
          * prototype to point to another Arguments object with a bigger argc.
@@ -849,17 +864,17 @@ ArgumentsObject::objectMovedDuringMinorG
  */
 const ClassOps MappedArgumentsObject::classOps_ = {
     nullptr,                 /* addProperty */
     ArgumentsObject::obj_delProperty,
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
     MappedArgumentsObject::obj_enumerate,
     MappedArgumentsObject::obj_resolve,
-    nullptr,                 /* mayResolve  */
+    ArgumentsObject::obj_mayResolve,
     ArgumentsObject::finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     ArgumentsObject::trace
 };
 
 const ObjectOps MappedArgumentsObject::objectOps_ = {
@@ -886,17 +901,17 @@ const Class MappedArgumentsObject::class
  */
 const ClassOps UnmappedArgumentsObject::classOps_ = {
     nullptr,                 /* addProperty */
     ArgumentsObject::obj_delProperty,
     nullptr,                 /* getProperty */
     nullptr,                 /* setProperty */
     UnmappedArgumentsObject::obj_enumerate,
     UnmappedArgumentsObject::obj_resolve,
-    nullptr,                 /* mayResolve  */
+    ArgumentsObject::obj_mayResolve,
     ArgumentsObject::finalize,
     nullptr,                 /* call        */
     nullptr,                 /* hasInstance */
     nullptr,                 /* construct   */
     ArgumentsObject::trace
 };
 
 const Class UnmappedArgumentsObject::class_ = {
--- a/js/src/vm/ArgumentsObject.h
+++ b/js/src/vm/ArgumentsObject.h
@@ -180,16 +180,18 @@ class ArgumentsObject : public NativeObj
         if (!data()->rareData && !createRareData(cx))
             return nullptr;
         return data()->rareData;
     }
 
     static bool obj_delProperty(JSContext* cx, HandleObject obj, HandleId id,
                                 ObjectOpResult& result);
 
+    static bool obj_mayResolve(const JSAtomState& names, jsid id, JSObject*);
+
   public:
     static const uint32_t RESERVED_SLOTS = 4;
     static const gc::AllocKind FINALIZE_KIND = gc::AllocKind::OBJECT4_BACKGROUND;
 
     /* Create an arguments object for a frame that is expecting them. */
     static ArgumentsObject* createExpected(JSContext* cx, AbstractFramePtr frame);
 
     /*
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -174,17 +174,21 @@ public:
           mContinuation = aContinuation;
       }
       mPurge = aPurge;
       if (!mActive && NS_SUCCEEDED(NS_DispatchToCurrentThread(this))) {
           mActive = true;
       }
   }
 
-  AsyncFreeSnowWhite() : mContinuation(false), mActive(false), mPurge(false) {}
+  AsyncFreeSnowWhite()
+    : Runnable("AsyncFreeSnowWhite")
+    , mContinuation(false)
+    , mActive(false)
+    , mPurge(false) {}
 
 public:
   bool mContinuation;
   bool mActive;
   bool mPurge;
 };
 
 namespace xpc {
@@ -3604,17 +3608,17 @@ XPCJSContext::BeforeProcessTask(bool aMi
     if (aMightBlock) {
         if (Promise::PerformMicroTaskCheckpoint()) {
             // If any microtask was processed, we post a dummy event in order to
             // force the ProcessNextEvent call not to block.  This is required
             // to support nested event loops implemented using a pattern like
             // "while (condition) thread.processNextEvent(true)", in case the
             // condition is triggered here by a Promise "then" callback.
 
-            NS_DispatchToMainThread(new Runnable());
+            NS_DispatchToMainThread(new Runnable("Empty_microtask_runnable"));
         }
     }
 
     // Start the slow script timer.
     mSlowScriptCheckpoint = mozilla::TimeStamp::NowLoRes();
     mSlowScriptSecondHalf = false;
     mSlowScriptActualWait = mozilla::TimeDuration();
     mTimeoutAccumulated = false;
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -2030,17 +2030,18 @@ PresShell::ResizeReflowIgnoreOverride(ns
       if (mAsyncResizeEventTimer) {
         mAsyncResizeTimerIsActive = true;
         mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback,
                                                      this, 15,
                                                      nsITimer::TYPE_ONE_SHOT);
       }
     } else {
       RefPtr<nsRunnableMethod<PresShell> > resizeEvent =
-        NewRunnableMethod(this, &PresShell::FireResizeEvent);
+        NewRunnableMethod("PresShell::FireResizeEvent",
+                          this, &PresShell::FireResizeEvent);
       if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) {
         mResizeEvent = resizeEvent;
         SetNeedStyleFlush();
       }
     }
   }
 
   return NS_OK; //XXX this needs to be real. MMP
@@ -6241,17 +6242,18 @@ PresShell::ScheduleApproximateFrameVisib
     return;
   }
 
   if (mUpdateApproximateFrameVisibilityEvent.IsPending()) {
     return;
   }
 
   RefPtr<nsRunnableMethod<PresShell> > ev =
-    NewRunnableMethod(this, &PresShell::UpdateApproximateFrameVisibility);
+    NewRunnableMethod("PresShell::UpdateApproximateFrameVisibility",
+                      this, &PresShell::UpdateApproximateFrameVisibility);
   if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
     mUpdateApproximateFrameVisibilityEvent = ev;
   }
 }
 
 void
 PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame)
 {
--- a/layout/base/ShapeUtils.cpp
+++ b/layout/base/ShapeUtils.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ShapeUtils.h"
 
 #include <cstdlib>
 
 #include "nsCSSRendering.h"
+#include "nsMargin.h"
 #include "nsRuleNode.h"
 #include "nsStyleCoord.h"
 #include "nsStyleStruct.h"
 #include "SVGContentUtils.h"
 
 namespace mozilla {
 
 nscoord
@@ -35,29 +36,36 @@ ShapeUtils::ComputeShapeRadius(const Sty
   }
   return length;
 }
 
 nsPoint
 ShapeUtils::ComputeCircleOrEllipseCenter(StyleBasicShape* const aBasicShape,
                                          const nsRect& aRefBox)
 {
+  MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Circle ||
+             aBasicShape->GetShapeType() == StyleBasicShapeType::Ellipse,
+             "The basic shape must be circle() or ellipse!");
+
   nsPoint topLeft, anchor;
   nsSize size(aRefBox.Size());
   nsImageRenderer::ComputeObjectAnchorPoint(aBasicShape->GetPosition(),
                                             size, size,
                                             &topLeft, &anchor);
   return nsPoint(anchor.x + aRefBox.x, anchor.y + aRefBox.y);
 }
 
 nscoord
 ShapeUtils::ComputeCircleRadius(StyleBasicShape* const aBasicShape,
                                 const nsPoint& aCenter,
                                 const nsRect& aRefBox)
 {
+  MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Circle,
+             "The basic shape must be circle()!");
+
   const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
   MOZ_ASSERT(coords.Length() == 1, "wrong number of arguments");
   nscoord r = 0;
   if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
     const auto styleShapeRadius = coords[0].GetEnumValue<StyleShapeRadius>();
     nscoord horizontal =
       ComputeShapeRadius(styleShapeRadius, aCenter.x, aRefBox.x, aRefBox.XMost());
     nscoord vertical =
@@ -77,16 +85,19 @@ ShapeUtils::ComputeCircleRadius(StyleBas
   return r;
 }
 
 nsSize
 ShapeUtils::ComputeEllipseRadii(StyleBasicShape* const aBasicShape,
                                 const nsPoint& aCenter,
                                 const nsRect& aRefBox)
 {
+  MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Ellipse,
+             "The basic shape must be ellipse()!");
+
   const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
   MOZ_ASSERT(coords.Length() == 2, "wrong number of arguments");
   nsSize radii;
 
   if (coords[0].GetUnit() == eStyleUnit_Enumerated) {
     const StyleShapeRadius radiusX = coords[0].GetEnumValue<StyleShapeRadius>();
     radii.width = ComputeShapeRadius(radiusX, aCenter.x, aRefBox.x,
                                      aRefBox.XMost());
@@ -100,9 +111,42 @@ ShapeUtils::ComputeEllipseRadii(StyleBas
                                       aRefBox.YMost());
   } else {
     radii.height = nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.height);
   }
 
   return radii;
 }
 
+/* static */ nsRect
+ShapeUtils::ComputeInsetRect(StyleBasicShape* const aBasicShape,
+                             const nsRect& aRefBox)
+{
+  MOZ_ASSERT(aBasicShape->GetShapeType() == StyleBasicShapeType::Inset,
+             "The basic shape must be inset()!");
+
+  const nsTArray<nsStyleCoord>& coords = aBasicShape->Coordinates();
+  MOZ_ASSERT(coords.Length() == 4, "wrong number of arguments");
+
+  nsMargin inset(nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.height),
+                 nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.width),
+                 nsRuleNode::ComputeCoordPercentCalc(coords[2], aRefBox.height),
+                 nsRuleNode::ComputeCoordPercentCalc(coords[3], aRefBox.width));
+
+  nsRect insetRect(aRefBox);
+  insetRect.Deflate(inset);
+
+  return insetRect;
+}
+
+/* static */ bool
+ShapeUtils::ComputeInsetRadii(StyleBasicShape* const aBasicShape,
+                              const nsRect& aInsetRect,
+                              const nsRect& aRefBox,
+                              nscoord aRadii[8])
+{
+  const nsStyleCorners& radius = aBasicShape->GetRadius();
+  return nsIFrame::ComputeBorderRadii(radius, aInsetRect.Size(), aRefBox.Size(),
+                                      Sides(), aRadii);
+
+}
+
 } // namespace mozilla
--- a/layout/base/ShapeUtils.h
+++ b/layout/base/ShapeUtils.h
@@ -21,25 +21,23 @@ class StyleBasicShape;
 // https://drafts.csswg.org/css-shapes/#basic-shape-functions
 //
 struct ShapeUtils final
 {
   // Compute the length of a keyword <shape-radius>, i.e. closest-side or
   // farthest-side, for a circle or an ellipse on a single dimension. The
   // caller needs to call for both dimensions and combine the result.
   // https://drafts.csswg.org/css-shapes/#typedef-shape-radius.
-  //
   // @return The length of the radius in app units.
   static nscoord ComputeShapeRadius(const StyleShapeRadius aType,
                                     const nscoord aCenter,
                                     const nscoord aPosMin,
                                     const nscoord aPosMax);
 
   // Compute the center of a circle or an ellipse.
-  //
   // @param aRefBox The reference box of the basic shape.
   // @return The point of the center.
   static nsPoint ComputeCircleOrEllipseCenter(
     StyleBasicShape* const aBasicShape,
     const nsRect& aRefBox);
 
   // Compute the radius for a circle.
   // @param aCenter the center of the circle.
@@ -52,13 +50,31 @@ struct ShapeUtils final
   // Compute the radii for an ellipse.
   // @param aCenter the center of the ellipse.
   // @param aRefBox the reference box of the ellipse.
   // @return The radii of the ellipse in app units. The width and height
   // represent the x-axis and y-axis radii of the ellipse.
   static nsSize ComputeEllipseRadii(
     mozilla::StyleBasicShape* const aBasicShape,
     const nsPoint& aCenter, const nsRect& aRefBox);
+
+  // Compute the rect for an inset.
+  // @param aRefBox the reference box of the inset.
+  // @return The inset rect in app units.
+  static nsRect ComputeInsetRect(
+    mozilla::StyleBasicShape* const aBasicShape,
+    const nsRect& aRefBox);
+
+  // Compute the radii for an inset.
+  // @param aRefBox the reference box of the inset.
+  // @param aInsetRect the inset rect computed by ComputeInsetRect().
+  // @param aRadii the returned radii in app units.
+  // @return true if any of the radii is nonzero; false otherwise.
+  static bool ComputeInsetRadii(
+    mozilla::StyleBasicShape* const aBasicShape,
+    const nsRect& aInsetRect,
+    const nsRect& aRefBox,
+    nscoord aRadii[8]);
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ShapeUtils_h
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -610,18 +610,19 @@ void nsCaret::ResetBlinking()
     if (NS_FAILED(err))
       return;
   }
 
   uint32_t blinkRate = static_cast<uint32_t>(
     LookAndFeel::GetInt(LookAndFeel::eIntID_CaretBlinkTime, 500));
   if (blinkRate > 0) {
     mBlinkCount = Preferences::GetInt("ui.caretBlinkCount", -1);
-    mBlinkTimer->InitWithFuncCallback(CaretBlinkCallback, this, blinkRate,
-                                      nsITimer::TYPE_REPEATING_SLACK);
+    mBlinkTimer->InitWithNamedFuncCallback(CaretBlinkCallback, this, blinkRate,
+                                           nsITimer::TYPE_REPEATING_SLACK,
+                                           "nsCaret::CaretBlinkCallback_timer");
   }
 }
 
 void nsCaret::StopBlinking()
 {
   if (mBlinkTimer)
   {
     mBlinkTimer->Cancel();
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -450,17 +450,17 @@ private:
 };
 
 }
 
 class nsDocumentShownDispatcher : public Runnable
 {
 public:
   explicit nsDocumentShownDispatcher(nsCOMPtr<nsIDocument> aDocument)
-  : mDocument(aDocument) {}
+    : Runnable("nsDocumentShownDispatcher"), mDocument(aDocument) {}
 
   NS_IMETHOD Run() override;
 
 private:
   nsCOMPtr<nsIDocument> mDocument;
 };
 
 
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -114,17 +114,18 @@ public:
 
 namespace {
 
 class CharSetChangingRunnable : public Runnable
 {
 public:
   CharSetChangingRunnable(nsPresContext* aPresContext,
                           const nsCString& aCharSet)
-    : mPresContext(aPresContext),
+    : Runnable("CharSetChangingRunnable"),
+      mPresContext(aPresContext),
       mCharSet(aCharSet)
   {
   }
 
   NS_IMETHOD Run() override
   {
     mPresContext->DoChangeCharSet(mCharSet);
     return NS_OK;
@@ -756,17 +757,18 @@ nsPresContext::PreferenceChanged(const c
   if (!mPrefChangedTimer)
   {
     // We will end up calling InvalidatePreferenceSheets one from each pres
     // context, but all it's doing is clearing its cached sheet pointers,
     // so it won't be wastefully recreating the sheet multiple times.
     // The first pres context that has its mPrefChangedTimer called will
     // be the one to cause the reconstruction of the pref style sheet.
     nsLayoutStylesheetCache::InvalidatePreferenceSheets();
-    mPrefChangedTimer = CreateTimer(PrefChangedUpdateTimerCallback, 0);
+    mPrefChangedTimer = CreateTimer(PrefChangedUpdateTimerCallback,
+                                    "PrefChangedUpdateTimerCallback", 0);
     if (!mPrefChangedTimer) {
       return;
     }
   }
   if (prefName.EqualsLiteral("nglayout.debug.paint_flashing") ||
       prefName.EqualsLiteral("nglayout.debug.paint_flashing_chrome")) {
     mPaintFlashingInitialized = false;
     return;
@@ -1512,17 +1514,18 @@ void
 nsPresContext::SetContainer(nsIDocShell* aDocShell)
 {
   if (aDocShell) {
     NS_ASSERTION(!(mContainer && mNeedsPrefUpdate),
                  "Should only need pref update if mContainer is null.");
     mContainer = static_cast<nsDocShell*>(aDocShell);
     if (mNeedsPrefUpdate) {
       if (!mPrefChangedTimer) {
-        mPrefChangedTimer = CreateTimer(PrefChangedUpdateTimerCallback, 0);
+        mPrefChangedTimer = CreateTimer(PrefChangedUpdateTimerCallback,
+                                        "PrefChangedUpdateTimerCallback", 0);
       }
       mNeedsPrefUpdate = false;
     }
   } else {
     mContainer = WeakPtr<nsDocShell>();
   }
   UpdateIsChrome();
   if (mContainer) {
@@ -2081,17 +2084,18 @@ nsPresContext::MediaFeatureValuesChanged
 void
 nsPresContext::PostMediaFeatureValuesChangedEvent()
 {
   // FIXME: We should probably replace this event with use of
   // nsRefreshDriver::AddStyleFlushObserver (except the pres shell would
   // need to track whether it's been added).
   if (!mPendingMediaFeatureValuesChanged && mShell) {
     nsCOMPtr<nsIRunnable> ev =
-      NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
+      NewRunnableMethod("nsPresContext::HandleMediaFeatureValuesChangedEvent",
+                        this, &nsPresContext::HandleMediaFeatureValuesChangedEvent);
     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
       mPendingMediaFeatureValuesChanged = true;
       mShell->SetNeedStyleFlush();
     }
   }
 }
 
 void
@@ -2273,17 +2277,18 @@ nsPresContext::RebuildCounterStyles()
   }
 
   mCounterStylesDirty = true;
   if (mShell) {
     mShell->SetNeedStyleFlush();
   }
   if (!mPostedFlushCounterStyles) {
     nsCOMPtr<nsIRunnable> ev =
-      NewRunnableMethod(this, &nsPresContext::HandleRebuildCounterStyles);
+      NewRunnableMethod("nsPresContext::HandleRebuildCounterStyles",
+                        this, &nsPresContext::HandleRebuildCounterStyles);
     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) {
       mPostedFlushCounterStyles = true;
     }
   }
 }
 
 void
 nsPresContext::NotifyMissingFonts()
@@ -2665,22 +2670,24 @@ nsPresContext::HasCachedStyleData()
     return mShell->DidInitialize();
   }
 
   return styleSet->HasCachedStyleData();
 }
 
 already_AddRefed<nsITimer>
 nsPresContext::CreateTimer(nsTimerCallbackFunc aCallback,
+                           const char* aName,
                            uint32_t aDelay)
 {
   nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
   if (timer) {
-    nsresult rv = timer->InitWithFuncCallback(aCallback, this, aDelay,
-                                              nsITimer::TYPE_ONE_SHOT);
+    nsresult rv = timer->InitWithNamedFuncCallback(aCallback, this, aDelay,
+                                                   nsITimer::TYPE_ONE_SHOT,
+                                                   aName);
     if (NS_SUCCEEDED(rv)) {
       return timer.forget();
     }
   }
 
   return nullptr;
 }
 
@@ -3086,16 +3093,17 @@ nsRootPresContext::InitApplyPluginGeomet
   // We'll apply the plugin geometry updates during the next compositing paint in this
   // presContext (either from nsPresShell::WillPaintWindow or from
   // nsPresShell::DidPaintWindow, depending on the platform).  But paints might
   // get optimized away if the old plugin geometry covers the invalid region,
   // so set a backup timer to do this too.  We want to make sure this
   // won't fire before our normal paint notifications, if those would
   // update the geometry, so set it for double the refresh driver interval.
   mApplyPluginGeometryTimer = CreateTimer(ApplyPluginGeometryUpdatesCallback,
+                                          "ApplyPluginGeometryUpdatesCallback",
                                           nsRefreshDriver::DefaultInterval() * 2);
 }
 
 void
 nsRootPresContext::CancelApplyPluginGeometryTimer()
 {
   if (mApplyPluginGeometryTimer) {
     mApplyPluginGeometryTimer->Cancel();
@@ -3265,17 +3273,19 @@ NotifyDidPaintForSubtreeCallback(nsITime
 }
 
 void
 nsRootPresContext::EnsureEventualDidPaintEvent()
 {
   if (mNotifyDidPaintTimer)
     return;
 
-  mNotifyDidPaintTimer = CreateTimer(NotifyDidPaintForSubtreeCallback, 100);
+  mNotifyDidPaintTimer = CreateTimer(NotifyDidPaintForSubtreeCallback,
+                                     "NotifyDidPaintForSubtreeCallback",
+                                     100);
 }
 
 void
 nsRootPresContext::AddWillPaintObserver(nsIRunnable* aRunnable)
 {
   if (!mWillPaintFallbackEvent.IsPending()) {
     mWillPaintFallbackEvent = new RunWillPaintObservers(this);
     NS_DispatchToMainThread(mWillPaintFallbackEvent.get());
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -1237,16 +1237,17 @@ protected:
   bool HavePendingInputEvent();
 
   // Can't be inline because we can't include nsStyleSet.h.
   bool HasCachedStyleData();
 
   // Creates a one-shot timer with the given aCallback & aDelay.
   // Returns a refcounted pointer to the timer (or nullptr on failure).
   already_AddRefed<nsITimer> CreateTimer(nsTimerCallbackFunc aCallback,
+                                         const char* aName,
                                          uint32_t aDelay);
 
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   nsPresContextType     mType;
   // the nsPresShell owns a strong reference to the nsPresContext, and is responsible
@@ -1580,17 +1581,19 @@ protected:
   void InitApplyPluginGeometryTimer();
   /**
    * Cancel the timer that ensures we eventually run ApplyPluginGeometryUpdates.
    */
   void CancelApplyPluginGeometryTimer();
 
   class RunWillPaintObservers : public mozilla::Runnable {
   public:
-    explicit RunWillPaintObservers(nsRootPresContext* aPresContext) : mPresContext(aPresContext) {}
+    explicit RunWillPaintObservers(nsRootPresContext* aPresContext)
+      : Runnable("nsPresContextType::RunWillPaintObservers")
+      , mPresContext(aPresContext) {}
     void Revoke() { mPresContext = nullptr; }
     NS_IMETHOD Run() override
     {
       if (mPresContext) {
         mPresContext->FlushWillPaintObservers();
       }
       return NS_OK;
     }
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -524,98 +524,52 @@ nsFloatManager::ClearContinues(StyleClea
           (aBreakType == StyleClear::Both ||
            aBreakType == StyleClear::Left)) ||
          ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
           (aBreakType == StyleClear::Both ||
            aBreakType == StyleClear::Right));
 }
 
 /////////////////////////////////////////////////////////////////////////////
-// BoxShapeInfo
+// RoundedBoxShapeInfo
 
 nscoord
-nsFloatManager::BoxShapeInfo::LineLeft(WritingMode aWM,
-                                       const nscoord aBStart,
-                                       const nscoord aBEnd) const
+nsFloatManager::RoundedBoxShapeInfo::LineLeft(WritingMode aWM,
+                                              const nscoord aBStart,
+                                              const nscoord aBEnd) const
 {
-  nscoord radii[8];
-  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-  if (!hasRadii) {
-    return mShapeBoxRect.x;
-  }
-
-  // Get the physical side for line-left since border-radii are in
-  // the physical axis.
-  mozilla::Side lineLeftSide =
-    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
-  nscoord blockStartCornerRadiusL =
-    radii[SideToHalfCorner(lineLeftSide, true, false)];
-  nscoord blockStartCornerRadiusB =
-    radii[SideToHalfCorner(lineLeftSide, true, true)];
-  nscoord blockEndCornerRadiusL =
-    radii[SideToHalfCorner(lineLeftSide, false, false)];
-  nscoord blockEndCornerRadiusB =
-    radii[SideToHalfCorner(lineLeftSide, false, true)];
-
-  if (aWM.IsLineInverted()) {
-    // This happens only when aWM is vertical-lr. Need to swap blockStart
-    // and blockEnd corners.
-    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+  if (!mRadii) {
+    return mRect.x;
   }
 
   nscoord lineLeftDiff =
     ComputeEllipseLineInterceptDiff(
-      mShapeBoxRect.y, mShapeBoxRect.YMost(),
-      blockStartCornerRadiusL, blockStartCornerRadiusB,
-      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      mRect.y, mRect.YMost(),
+      mRadii[eCornerTopLeftX], mRadii[eCornerTopLeftY],
+      mRadii[eCornerBottomLeftX], mRadii[eCornerBottomLeftY],
       aBStart, aBEnd);
-  return mShapeBoxRect.x + lineLeftDiff;
+  return mRect.x + lineLeftDiff;
 }
 
 nscoord
-nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
-                                        const nscoord aBStart,
-                                        const nscoord aBEnd) const
+nsFloatManager::RoundedBoxShapeInfo::LineRight(WritingMode aWM,
+                                               const nscoord aBStart,
+                                               const nscoord aBEnd) const
 {
-  nscoord radii[8];
-  bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
-  if (!hasRadii) {
-    return mShapeBoxRect.XMost();
-  }
-
-  // Get the physical side for line-right since border-radii are in
-  // the physical axis.
-  mozilla::Side lineRightSide =
-    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
-  nscoord blockStartCornerRadiusL =
-    radii[SideToHalfCorner(lineRightSide, false, false)];
-  nscoord blockStartCornerRadiusB =
-    radii[SideToHalfCorner(lineRightSide, false, true)];
-  nscoord blockEndCornerRadiusL =
-    radii[SideToHalfCorner(lineRightSide, true, false)];
-  nscoord blockEndCornerRadiusB =
-    radii[SideToHalfCorner(lineRightSide, true, true)];
-
-  if (aWM.IsLineInverted()) {
-    // This happens only when aWM is vertical-lr. Need to swap blockStart
-    // and blockEnd corners.
-    std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
-    std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+  if (!mRadii) {
+    return mRect.XMost();
   }
 
   nscoord lineRightDiff =
     ComputeEllipseLineInterceptDiff(
-      mShapeBoxRect.y, mShapeBoxRect.YMost(),
-      blockStartCornerRadiusL, blockStartCornerRadiusB,
-      blockEndCornerRadiusL, blockEndCornerRadiusB,
+      mRect.y, mRect.YMost(),
+      mRadii[eCornerTopRightX], mRadii[eCornerTopRightY],
+      mRadii[eCornerBottomRightX], mRadii[eCornerBottomRightY],
       aBStart, aBEnd);
-  return mShapeBoxRect.XMost() - lineRightDiff;
+  return mRect.XMost() - lineRightDiff;
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // EllipseShapeInfo
 nscoord
 nsFloatManager::EllipseShapeInfo::LineLeft(WritingMode aWM,
                                            const nscoord aBStart,
                                            const nscoord aBEnd) const
@@ -645,20 +599,18 @@ nsFloatManager::EllipseShapeInfo::LineRi
 // FloatInfo
 
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
                                      nscoord aLineLeft, nscoord aBlockStart,
                                      const LogicalRect& aMarginRect,
                                      WritingMode aWM,
                                      const nsSize& aContainerSize)
   : mFrame(aFrame)
-  , mRect(aMarginRect.LineLeft(aWM, aContainerSize) + aLineLeft,
-          aMarginRect.BStart(aWM) + aBlockStart,
-          aMarginRect.ISize(aWM),
-          aMarginRect.BSize(aWM))
+  , mRect(ShapeInfo::ConvertToFloatLogical(aMarginRect, aWM, aContainerSize) +
+          nsPoint(aLineLeft, aBlockStart))
 {
   MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
 
   const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
 
   if (shapeOutside.GetType() == StyleShapeSourceType::None) {
     return;
   }
@@ -666,58 +618,40 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
   if (shapeOutside.GetType() == StyleShapeSourceType::URL) {
     // Bug 1265343: Implement 'shape-image-threshold'. Early return
     // here because shape-outside with url() value doesn't have a
     // reference box, and GetReferenceBox() asserts that.
     return;
   }
 
   // Initialize <shape-box>'s reference rect.
-  LogicalRect rect = aMarginRect;
-
-  switch (shapeOutside.GetReferenceBox()) {
-    case StyleShapeOutsideShapeBox::Content:
-      rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
-      MOZ_FALLTHROUGH;
-    case StyleShapeOutsideShapeBox::Padding:
-      rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
-      MOZ_FALLTHROUGH;
-    case StyleShapeOutsideShapeBox::Border:
-      rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
-      break;
-    case StyleShapeOutsideShapeBox::Margin:
-      // Do nothing. rect is already a margin rect.
-      break;
-    case StyleShapeOutsideShapeBox::NoBox:
-      MOZ_ASSERT(shapeOutside.GetType() != StyleShapeSourceType::Box,
-                 "Box source type must have <shape-box> specified!");
-      break;
-  }
+  LogicalRect shapeBoxRect =
+    ShapeInfo::ComputeShapeBoxRect(shapeOutside, mFrame, aMarginRect, aWM);
 
   if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
-    nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize), rect.BStart(aWM),
-                        rect.ISize(aWM), rect.BSize(aWM));
-    mShapeInfo = MakeUnique<BoxShapeInfo>(shapeBoxRect, mFrame);
+    mShapeInfo = ShapeInfo::CreateShapeBox(mFrame, shapeBoxRect, aWM,
+                                           aContainerSize);
   } else if (shapeOutside.GetType() == StyleShapeSourceType::Shape) {
     StyleBasicShape* const basicShape = shapeOutside.GetBasicShape();
 
     switch (basicShape->GetShapeType()) {
       case StyleBasicShapeType::Polygon:
         // Bug 1326409 - Implement the rendering of basic shape polygon()
         // for CSS shape-outside.
         return;
       case StyleBasicShapeType::Circle:
       case StyleBasicShapeType::Ellipse:
         mShapeInfo =
-          ShapeInfo::CreateCircleOrEllipse(basicShape, rect, aWM, aContainerSize);
+          ShapeInfo::CreateCircleOrEllipse(basicShape, shapeBoxRect, aWM,
+                                           aContainerSize);
         break;
       case StyleBasicShapeType::Inset:
-        // Bug 1326407 - Implement the rendering of basic shape inset() for
-        // CSS shape-outside.
-        return;
+        mShapeInfo =
+          ShapeInfo::CreateInset(basicShape, shapeBoxRect, aWM, aContainerSize);
+        break;
     }
   } else {
     MOZ_ASSERT_UNREACHABLE("Unknown StyleShapeSourceType!");
   }
 
   MOZ_ASSERT(mShapeInfo,
              "All shape-outside values except none should have mShapeInfo!");
 
@@ -823,32 +757,117 @@ nsFloatManager::FloatInfo::IsEmpty(Shape
     return IsEmpty();
   }
   return mShapeInfo->IsEmpty();
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // ShapeInfo
 
+/* static */ LogicalRect
+nsFloatManager::ShapeInfo::ComputeShapeBoxRect(
+  const StyleShapeOutside& aShapeOutside,
+  nsIFrame* const aFrame,
+  const mozilla::LogicalRect& aMarginRect,
+  mozilla::WritingMode aWM)
+{
+  LogicalRect rect = aMarginRect;
+
+  switch (aShapeOutside.GetReferenceBox()) {
+    case StyleShapeOutsideShapeBox::Content:
+      rect.Deflate(aWM, aFrame->GetLogicalUsedPadding(aWM));
+      MOZ_FALLTHROUGH;
+    case StyleShapeOutsideShapeBox::Padding:
+      rect.Deflate(aWM, aFrame->GetLogicalUsedBorder(aWM));
+      MOZ_FALLTHROUGH;
+    case StyleShapeOutsideShapeBox::Border:
+      rect.Deflate(aWM, aFrame->GetLogicalUsedMargin(aWM));
+      break;
+    case StyleShapeOutsideShapeBox::Margin:
+      // Do nothing. rect is already a margin rect.
+      break;
+    case StyleShapeOutsideShapeBox::NoBox:
+      MOZ_ASSERT(aShapeOutside.GetType() != StyleShapeSourceType::Box,
+                 "Box source type must have <shape-box> specified!");
+      break;
+  }
+
+  return rect;
+}
+
+/* static */ UniquePtr<nsFloatManager::ShapeInfo>
+nsFloatManager::ShapeInfo::CreateShapeBox(
+  nsIFrame* const aFrame,
+  const LogicalRect& aShapeBoxRect,
+  WritingMode aWM,
+  const nsSize& aContainerSize)
+{
+  nsRect logicalShapeBoxRect
+    = ConvertToFloatLogical(aShapeBoxRect, aWM, aContainerSize);
+
+  nscoord physicalRadii[8];
+  bool hasRadii = aFrame->GetShapeBoxBorderRadii(physicalRadii);
+  if (!hasRadii) {
+    return MakeUnique<RoundedBoxShapeInfo>(logicalShapeBoxRect,
+                                           UniquePtr<nscoord[]>());
+  }
+
+  return MakeUnique<RoundedBoxShapeInfo>(logicalShapeBoxRect,
+                                         ConvertToFloatLogical(physicalRadii,
+                                                               aWM));
+}
+
+/* static */ UniquePtr<nsFloatManager::ShapeInfo>
+nsFloatManager::ShapeInfo::CreateInset(
+  StyleBasicShape* const aBasicShape,
+  const LogicalRect& aShapeBoxRect,
+  WritingMode aWM,
+  const nsSize& aContainerSize)
+{
+  // Use physical coordinates to compute inset() because the top, right,
+  // bottom and left offsets are physical.
+  // https://drafts.csswg.org/css-shapes-1/#funcdef-inset
+  nsRect physicalShapeBoxRect =
+    aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
+  nsRect insetRect =
+    ShapeUtils::ComputeInsetRect(aBasicShape, physicalShapeBoxRect);
+
+  nsRect logicalInsetRect =
+    ConvertToFloatLogical(LogicalRect(aWM, insetRect, aContainerSize),
+                          aWM, aContainerSize);
+  nscoord physicalRadii[8];
+  bool hasRadii =
+    ShapeUtils::ComputeInsetRadii(aBasicShape, insetRect, physicalShapeBoxRect,
+                                  physicalRadii);
+  if (!hasRadii) {
+    return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
+                                           UniquePtr<nscoord[]>());
+  }
+
+  return MakeUnique<RoundedBoxShapeInfo>(logicalInsetRect,
+                                         ConvertToFloatLogical(physicalRadii,
+                                                               aWM));
+}
+
 /* static */ UniquePtr<nsFloatManager::ShapeInfo>
 nsFloatManager::ShapeInfo::CreateCircleOrEllipse(
   StyleBasicShape* const aBasicShape,
   const LogicalRect& aShapeBoxRect,
   WritingMode aWM,
   const nsSize& aContainerSize)
 {
   // Use physical coordinates to compute the center of circle() or ellipse()
   // since the <position> keywords such as 'left', 'top', etc. are physical.
   // https://drafts.csswg.org/css-shapes-1/#funcdef-ellipse
   nsRect physicalShapeBoxRect =
     aShapeBoxRect.GetPhysicalRect(aWM, aContainerSize);
   nsPoint physicalCenter =
     ShapeUtils::ComputeCircleOrEllipseCenter(aBasicShape, physicalShapeBoxRect);
-  nsPoint center =
-    ConvertPhysicalToLogical(aWM, physicalCenter, aContainerSize);
+  nsPoint logicalCenter =
+    ConvertToFloatLogical(physicalCenter, aWM, aContainerSize);
 
   // Compute the circle or ellipse radii.
   nsSize radii;
   StyleBasicShapeType type = aBasicShape->GetShapeType();
   if (type == StyleBasicShapeType::Circle) {
     nscoord radius = ShapeUtils::ComputeCircleRadius(aBasicShape, physicalCenter,
                                                      physicalShapeBoxRect);
     radii = nsSize(radius, radius);
@@ -856,17 +875,17 @@ nsFloatManager::ShapeInfo::CreateCircleO
     MOZ_ASSERT(type == StyleBasicShapeType::Ellipse);
     nsSize physicalRadii =
       ShapeUtils::ComputeEllipseRadii(aBasicShape, physicalCenter,
                                       physicalShapeBoxRect);
     LogicalSize logicalRadii(aWM, physicalRadii);
     radii = nsSize(logicalRadii.ISize(aWM), logicalRadii.BSize(aWM));
   }
 
-  return MakeUnique<EllipseShapeInfo>(center, radii);
+  return MakeUnique<EllipseShapeInfo>(logicalCenter, radii);
 }
 
 
 /* static */ nscoord
 nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
   const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
   const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
   const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
@@ -941,26 +960,71 @@ nsFloatManager::ShapeInfo::XInterceptAtY
                                          const nscoord aRadiusY)
 {
   // Solve for x in the ellipse equation (x/radiusX)^2 + (y/radiusY)^2 = 1.
   MOZ_ASSERT(aRadiusY > 0);
   return aRadiusX * std::sqrt(1 - (aY * aY) / double(aRadiusY * aRadiusY));
 }
 
 /* static */ nsPoint
-nsFloatManager::ShapeInfo::ConvertPhysicalToLogical(
+nsFloatManager::ShapeInfo::ConvertToFloatLogical(
+  const nsPoint& aPoint,
   WritingMode aWM,
-  const nsPoint& aPoint,
   const nsSize& aContainerSize)
 {
   LogicalPoint logicalPoint(aWM, aPoint, aContainerSize);
   return nsPoint(logicalPoint.LineRelative(aWM, aContainerSize),
                  logicalPoint.B(aWM));
 }
 
+/* static */ UniquePtr<nscoord[]>
+nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8],
+                                                 WritingMode aWM)
+{
+  UniquePtr<nscoord[]> logicalRadii(new nscoord[8]);
+
+  // Get the physical side for line-left and line-right since border radii
+  // are on the physical axis.
+  Side lineLeftSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
+  logicalRadii[eCornerTopLeftX] =
+    aRadii[SideToHalfCorner(lineLeftSide, true, false)];
+  logicalRadii[eCornerTopLeftY] =
+    aRadii[SideToHalfCorner(lineLeftSide, true, true)];
+  logicalRadii[eCornerBottomLeftX] =
+    aRadii[SideToHalfCorner(lineLeftSide, false, false)];
+  logicalRadii[eCornerBottomLeftY] =
+    aRadii[SideToHalfCorner(lineLeftSide, false, true)];
+
+  Side lineRightSide =
+    aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
+  logicalRadii[eCornerTopRightX] =
+    aRadii[SideToHalfCorner(lineRightSide, false, false)];
+  logicalRadii[eCornerTopRightY] =
+    aRadii[SideToHalfCorner(lineRightSide, false, true)];
+  logicalRadii[eCornerBottomRightX] =
+    aRadii[SideToHalfCorner(lineRightSide, true, false)];
+  logicalRadii[eCornerBottomRightY] =
+    aRadii[SideToHalfCorner(lineRightSide, true, true)];
+
+  if (aWM.IsLineInverted()) {
+    // When IsLineInverted() is true, i.e. aWM is vertical-lr,
+    // line-over/line-under are inverted from block-start/block-end. So the
+    // relationship reverses between which corner comes first going
+    // clockwise, and which corner is block-start versus block-end. We need
+    // to swap the values stored in top and bottom corners.
+    std::swap(logicalRadii[eCornerTopLeftX], logicalRadii[eCornerBottomLeftX]);
+    std::swap(logicalRadii[eCornerTopLeftY], logicalRadii[eCornerBottomLeftY]);
+    std::swap(logicalRadii[eCornerTopRightX], logicalRadii[eCornerBottomRightX]);
+    std::swap(logicalRadii[eCornerTopRightY], logicalRadii[eCornerBottomRightY]);
+  }
+
+  return logicalRadii;
+}
+
 //----------------------------------------------------------------------
 
 nsAutoFloatManager::~nsAutoFloatManager()
 {
   // Restore the old float manager in the reflow input if necessary.
   if (mNew) {
 #ifdef DEBUG
     if (nsBlockFrame::gNoisyFloatManager) {
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -356,16 +356,44 @@ private:
                               const nscoord aBEnd) const = 0;
     virtual nscoord BStart() const = 0;
     virtual nscoord BEnd() const = 0;
     virtual bool IsEmpty() const = 0;
 
     // Translate the current origin by the specified offsets.
     virtual void Translate(nscoord aLineLeft, nscoord aBlockStart) = 0;
 
+    static mozilla::LogicalRect ComputeShapeBoxRect(
+      const mozilla::StyleShapeOutside& aShapeOutside,
+      nsIFrame* const aFrame,
+      const mozilla::LogicalRect& aMarginRect,
+      mozilla::WritingMode aWM);
+
+    // Convert the LogicalRect to the special logical coordinate space used
+    // in float manager.
+    static nsRect ConvertToFloatLogical(const mozilla::LogicalRect& aRect,
+                                        mozilla::WritingMode aWM,
+                                        const nsSize& aContainerSize)
+    {
+      return nsRect(aRect.LineLeft(aWM, aContainerSize), aRect.BStart(aWM),
+                    aRect.ISize(aWM), aRect.BSize(aWM));
+    }
+
+    static mozilla::UniquePtr<ShapeInfo> CreateShapeBox(
+      nsIFrame* const aFrame,
+      const mozilla::LogicalRect& aShapeBoxRect,
+      mozilla::WritingMode aWM,
+      const nsSize& aContainerSize);
+
+    static mozilla::UniquePtr<ShapeInfo> CreateInset(
+      mozilla::StyleBasicShape* const aBasicShape,
+      const mozilla::LogicalRect& aShapeBoxRect,
+      mozilla::WritingMode aWM,
+      const nsSize& aContainerSize);
+
     static mozilla::UniquePtr<ShapeInfo> CreateCircleOrEllipse(
       mozilla::StyleBasicShape* const aBasicShape,
       const mozilla::LogicalRect& aShapeBoxRect,
       mozilla::WritingMode aWM,
       const nsSize& aContainerSize);
 
   protected:
     // Compute the minimum line-axis difference between the bounding shape
@@ -380,55 +408,62 @@ private:
       const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
       const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
       const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
       const nscoord aBandBStart, const nscoord aBandBEnd);
 
     static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
                                  const nscoord aRadiusY);
 
-    // Convert the coordinate space from physical to the logical space used
-    // in nsFloatManager, which is the same as FloatInfo::mRect.
-    static nsPoint ConvertPhysicalToLogical(mozilla::WritingMode aWM,
-                                            const nsPoint& aPoint,
-                                            const nsSize& aContainerSize);
+    // Convert the physical point to the special logical coordinate space
+    // used in float manager.
+    static nsPoint ConvertToFloatLogical(const nsPoint& aPoint,
+                                         mozilla::WritingMode aWM,
+                                         const nsSize& aContainerSize);
+
+    // Convert the half corner radii (nscoord[8]) to the special logical
+    // coordinate space used in float manager.
+    static mozilla::UniquePtr<nscoord[]> ConvertToFloatLogical(
+      const nscoord aRadii[8],
+      mozilla::WritingMode aWM);
   };
 
-  // Implements shape-outside: <shape-box>.
-  class BoxShapeInfo final : public ShapeInfo
+  // Implements shape-outside: <shape-box> and shape-outside: inset().
+  class RoundedBoxShapeInfo final : public ShapeInfo
   {
   public:
-    BoxShapeInfo(const nsRect& aShapeBoxRect, nsIFrame* const aFrame)
-      : mShapeBoxRect(aShapeBoxRect)
-      , mFrame(aFrame)
-    {
-    }
+    RoundedBoxShapeInfo(const nsRect& aRect,
+                        mozilla::UniquePtr<nscoord[]> aRadii)
+      : mRect(aRect)
+      , mRadii(Move(aRadii))
+    {}
 
     nscoord LineLeft(mozilla::WritingMode aWM,
                      const nscoord aBStart,
                      const nscoord aBEnd) const override;
     nscoord LineRight(mozilla::WritingMode aWM,
                       const nscoord aBStart,
                       const nscoord aBEnd) const override;
-    nscoord BStart() const override { return mShapeBoxRect.y; }
-    nscoord BEnd() const override { return mShapeBoxRect.YMost(); }
-    bool IsEmpty() const override { return mShapeBoxRect.IsEmpty(); };
+    nscoord BStart() const override { return mRect.y; }
+    nscoord BEnd() const override { return mRect.YMost(); }
+    bool IsEmpty() const override { return mRect.IsEmpty(); };
 
     void Translate(nscoord aLineLeft, nscoord aBlockStart) override
     {
-      mShapeBoxRect.MoveBy(aLineLeft, aBlockStart);
+      mRect.MoveBy(aLineLeft, aBlockStart);
     }
 
   private:
-    // This is the reference box of css shape-outside if specified, which
-    // implements the <shape-box> value in the CSS Shapes Module Level 1.
-    // The coordinate space is the same as FloatInfo::mRect.
-    nsRect mShapeBoxRect;
-    // The frame of the float.
-    nsIFrame* const mFrame;
+    // The rect of the rounded box shape in the float manager's coordinate
+    // space.
+    nsRect mRect;
+    // The half corner radii of the reference box. It's an nscoord[8] array
+    // in the float manager's coordinate space. If there are no radii, it's
+    // nullptr.
+    mozilla::UniquePtr<nscoord[]> mRadii;
   };
 
   // Implements shape-outside: circle() and shape-outside: ellipse().
   class EllipseShapeInfo : public ShapeInfo
   {
   public:
     EllipseShapeInfo(const nsPoint& aCenter,
                      const nsSize& aRadii)
--- a/layout/reftests/w3c-css/submitted/shapes1/reftest.list
+++ b/layout/reftests/w3c-css/submitted/shapes1/reftest.list
@@ -78,8 +78,22 @@ fails == shape-outside-border-box-border
 == shape-outside-ellipse-013.html shape-outside-ellipse-013-ref.html
 == shape-outside-ellipse-014.html shape-outside-ellipse-014-ref.html
 == shape-outside-ellipse-015.html shape-outside-ellipse-015-ref.html
 == shape-outside-ellipse-016.html shape-outside-ellipse-016-ref.html
 == shape-outside-ellipse-017.html shape-outside-ellipse-017-ref.html
 == shape-outside-ellipse-018.html shape-outside-ellipse-018-ref.html
 == shape-outside-ellipse-019.html shape-outside-ellipse-019-ref.html
 == shape-outside-ellipse-020.html shape-outside-ellipse-020-ref.html
+
+# Basic shape: inset()
+== shape-outside-inset-001.html shape-outside-inset-001-ref.html
+== shape-outside-inset-002.html shape-outside-inset-002-ref.html
+== shape-outside-inset-003.html shape-outside-inset-003-ref.html
+== shape-outside-inset-004.html shape-outside-inset-004-ref.html
+== shape-outside-inset-005.html shape-outside-inset-005-ref.html
+== shape-outside-inset-006.html shape-outside-inset-006-ref.html
+== shape-outside-inset-007.html shape-outside-inset-007-ref.html
+== shape-outside-inset-008.html shape-outside-inset-008-ref.html
+== shape-outside-inset-009.html shape-outside-inset-009-ref.html
+== shape-outside-inset-010.html shape-outside-inset-010-ref.html
+== shape-outside-inset-011.html shape-outside-inset-011-ref.html
+== shape-outside-inset-012.html shape-outside-inset-012-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-001-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, inset(20px) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(20px) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="height: 40px; top: 0; left: 0;"></div> <!-- Fill the margin and inset space -->
+    <div class="box" style="height: 40px; top: 40px; left: 120px;"></div>
+    <div class="box" style="height: 40px; top: 80px; left: 120px;"></div>
+    <div class="long box" style="height: 40px; top: 120px; left: 0;"></div> <!-- Fill the margin and inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-001.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, inset(20px) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-001-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the inset(20px) border-box value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(20px) border-box;
+    clip-path: inset(20px) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="height: 40px;"></div> <!-- Fill the margin and inset space -->
+    <div class="box" style="height: 40px;"></div>
+    <div class="box" style="height: 40px;"></div>
+    <div class="long box" style="height: 40px;"></div> <!-- Fill the margin and inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-002-ref.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, inset(20px) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(20px) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="height: 40px; top: 0; right: 0;"></div> <!-- Fill the margin and inset space -->
+    <div class="box" style="height: 40px; top: 40px; right: 120px;"></div>
+    <div class="box" style="height: 40px; top: 80px; right: 120px;"></div>
+    <div class="long box" style="height: 40px; top: 120px; right: 0;"></div> <!-- Fill the margin and inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-002.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, inset(20px) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-002-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the inset(20px) border-box value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(20px) border-box;
+    clip-path: inset(20px) border-box;
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 60px;
+    background-color: blue;
+  }
+
+  .long {
+    width: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="height: 40px;"></div> <!-- Fill the margin and inset space -->
+    <div class="box" style="height: 40px;"></div>
+    <div class="box" style="height: 40px;"></div>
+    <div class="long box" style="height: 40px;"></div> <!-- Fill the margin and inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-003-ref.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, inset(50%) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(50%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 24px; top: 0; left: 0;"></div>
+    <div class="box" style="height: 36px; top: 24px; left: 0;"></div>
+    <div class="box" style="height: 36px; top: 60px; left: 0;"></div>
+    <div class="box" style="height: 24px; top: 96px; left: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-003.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float left, inset(50%)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-003-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the left float shape defines an empty float area by the basic shape inset(50%) value.">
+  <style>
+  .container {
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(50%);
+    clip-path: inset(50%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 24px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 24px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-004-ref.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, inset(50%) reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    direction: rtl;
+    position: absolute;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(50%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 24px; top: 0; right: 0;"></div>
+    <div class="box" style="height: 36px; top: 24px; right: 0;"></div>
+    <div class="box" style="height: 36px; top: 60px; right: 0;"></div>
+    <div class="box" style="height: 24px; top: 96px; right: 0;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-004.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: float right, inset(50%)</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-004-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the right float shape defines an empty float area by the basic shape inset(50%) value.">
+  <style>
+  .container {
+    direction: rtl;
+    width: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(50%);
+    clip-path: inset(50%);
+    box-sizing: content-box;
+    height: 40px;
+    width: 40px;
+    padding: 20px;
+    border: 20px solid lightgreen;
+    margin: 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    width: 200px;
+    background-color: blue;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="box" style="height: 24px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 36px;"></div>
+    <div class="box" style="height: 24px;"></div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-005-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float left, inset(10px round 0 40px/ 0 60px) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 0 40px/ 0 60px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px 10px;
+    border: solid lightgreen;
+    border-width: 30px 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-005.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float left, inset(10px round 0 40px/ 0 60px) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-005-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the inset(10px round 0 40px/ 0 60px) border-box value under horizontal-tb writing-mode.">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(10px round 0 40px/ 0 60px) border-box;
+    clip-path: inset(10px round 0 40px/ 0 60px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px 10px;
+    border: solid lightgreen;
+    border-width: 30px 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-006-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float right, inset(10px round 0 40px/ 0 60px) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 0 40px/ 0 60px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px 10px;
+    border: solid lightgreen;
+    border-width: 30px 20px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-006.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: horizontal-tb, float right, inset(10px round 0 40px/ 0 60px) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-006-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the inset(10px round 0 40px/ 0 60px) border-box value under horizontal-tb writing-mode.">
+  <style>
+  .container {
+    writing-mode: horizontal-tb;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(10px round 0 40px/ 0 60px) border-box;
+    clip-path: inset(10px round 0 40px/ 0 60px) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 20px 10px;
+    border: solid lightgreen;
+    border-width: 30px 20px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-007-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float left, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-007.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float left, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-007-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under vertical-rl writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-008-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float right, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-008.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-rl, float right, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-008-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under vertical-rl writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-rl;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-009-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float left, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-009.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float left, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-009-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under vertical-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-010-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float right, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-010.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: vertical-lr, float right, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-010-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under vertical-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: vertical-lr;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-011-ref.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float left, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-011.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float left, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-011-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the left float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under sideways-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: left;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-012-ref.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float right, inset(10px round 60px 0/ 40px 0) border-box reference</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    direction: rtl;
+    position: absolute;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    /* Omit shape-outside */
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    position: absolute;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px; offset-block-start: 0px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px; offset-block-start: 10px; offset-inline-start: 90px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px; offset-block-start: 34px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 36px; offset-block-start: 70px; offset-inline-start: 90px;"></div>
+    <div class="box" style="block-size: 24px; offset-block-start: 106px; offset-inline-start: 82px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px; offset-block-start: 130px; offset-inline-start: 0px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/w3c-css/submitted/shapes1/shape-outside-inset-012.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <meta charset="utf-8">
+  <title>CSS Shape Test: sideways-lr, float right, inset(10px round 60px 0/ 40px 0) border-box</title>
+  <link rel="author" title="Ting-Yu Lin" href="mailto:tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-1/#supported-basic-shapes">
+  <link rel="match" href="shape-outside-inset-012-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Test the boxes are wrapping around the right float shape defined by the inset(10px round 60px 0/ 40px 0) border-box value under sideways-lr writing-mode.">
+  <style>
+  .container {
+    writing-mode: sideways-lr;
+    direction: rtl;
+    inline-size: 200px;
+    line-height: 0;
+  }
+
+  .shape {
+    float: right;
+    shape-outside: inset(10px round 60px 0/ 40px 0) border-box;
+    clip-path: inset(10px round 60px 0/ 40px 0) border-box;
+    box-sizing: content-box;
+    block-size: 40px;
+    inline-size: 40px;
+    padding: 10px 20px;
+    border: solid lightgreen;
+    border-width: 20px 30px;
+    background-color: orange;
+  }
+
+  .box {
+    display: inline-block;
+    inline-size: 80px;
+    background-color: blue;
+  }
+
+  .long {
+    inline-size: 200px;
+  }
+  </style>
+
+  <body class="container">
+    <div class="shape"></div>
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 36px;"></div>
+    <div class="box" style="block-size: 24px;"></div> <!-- Box at corner -->
+    <div class="long box" style="block-size: 10px;"></div> <!-- Fill the inset space -->
+  </body>
+</html>
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -23,17 +23,19 @@
 
 #ifdef CSS_REPORT_PARSE_ERRORS
 
 using namespace mozilla;
 
 namespace {
 class ShortTermURISpecCache : public Runnable {
 public:
-  ShortTermURISpecCache() : mPending(false) {}
+  ShortTermURISpecCache()
+   : Runnable("ShortTermURISpecCache")
+   , mPending(false) {}
 
   nsString const& GetSpec(nsIURI* aURI) {
     if (mURI != aURI) {
       mURI = aURI;
 
       nsAutoCString cSpec;
       nsresult rv = mURI->GetSpec(cSpec);
       if (NS_FAILED(rv)) {
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -1463,17 +1463,18 @@ FontFaceSet::OnFontFaceStatusChanged(Fon
     // relevant elements in the document.  We want to wait until the reflow
     // request has been done before the FontFaceSet is marked as Loaded so
     // that we don't briefly set the FontFaceSet to Loaded and then Loading
     // again once the reflow is pending.  So we go around the event loop
     // and call CheckLoadingFinished() after the reflow has been queued.
     if (!mDelayedLoadCheck) {
       mDelayedLoadCheck = true;
       nsCOMPtr<nsIRunnable> checkTask =
-        NewRunnableMethod(this, &FontFaceSet::CheckLoadingFinishedAfterDelay);
+        NewRunnableMethod("FontFaceSet::CheckLoadingFinishedAfterDelay",
+                          this, &FontFaceSet::CheckLoadingFinishedAfterDelay);
       NS_DispatchToMainThread(checkTask);
     }
   }
 }
 
 void
 FontFaceSet::DidRefresh()
 {
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -172,38 +172,28 @@ nsCSSClipPathInstance::CreateClipPathPol
   return builder->Finish();
 }
 
 already_AddRefed<Path>
 nsCSSClipPathInstance::CreateClipPathInset(DrawTarget* aDrawTarget,
                                            const nsRect& aRefBox)
 {
   StyleBasicShape* basicShape = mClipPathStyle.GetBasicShape();
-  const nsTArray<nsStyleCoord>& coords = basicShape->Coordinates();
-  MOZ_ASSERT(coords.Length() == 4, "wrong number of arguments");
 
   RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
 
   nscoord appUnitsPerDevPixel =
     mTargetFrame->PresContext()->AppUnitsPerDevPixel();
 
-  nsMargin inset(nsRuleNode::ComputeCoordPercentCalc(coords[0], aRefBox.height),
-                 nsRuleNode::ComputeCoordPercentCalc(coords[1], aRefBox.width),
-                 nsRuleNode::ComputeCoordPercentCalc(coords[2], aRefBox.height),
-                 nsRuleNode::ComputeCoordPercentCalc(coords[3], aRefBox.width));
-
-  nsRect insetRect(aRefBox);
-  insetRect.Deflate(inset);
+  nsRect insetRect = ShapeUtils::ComputeInsetRect(basicShape, aRefBox);
   const Rect insetRectPixels = NSRectToRect(insetRect, appUnitsPerDevPixel);
-  const nsStyleCorners& radius = basicShape->GetRadius();
-
   nscoord appUnitsRadii[8];
 
-  if (nsIFrame::ComputeBorderRadii(radius, insetRect.Size(), aRefBox.Size(),
-                                   Sides(), appUnitsRadii)) {
+  if (ShapeUtils::ComputeInsetRadii(basicShape, insetRect, aRefBox,
+                                    appUnitsRadii)) {
     RectCornerRadii corners;
     nsCSSRendering::ComputePixelRadii(appUnitsRadii,
                                       appUnitsPerDevPixel, &corners);
 
     AppendRoundedRectToPath(builder, insetRectPixels, corners, true);
   } else {
     AppendRectToPath(builder, insetRectPixels, true);
   }
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -79,18 +79,18 @@ class ReftestRunner(MozbuildObject):
         args.extraProfileFiles.append(os.path.join(self.topobjdir, "dist", "plugins"))
         args.symbolsPath = os.path.join(self.topobjdir, "crashreporter-symbols")
 
         if not args.tests:
             args.tests = [os.path.join(*default_manifest[args.suite])]
 
         if args.suite == "jstestbrowser":
             args.extraProfileFiles.append(os.path.join(self.topobjdir, "dist",
-                                                            "test-stage", "jsreftest",
-                                                            "tests", "user.js"))
+                                                       "test-stage", "jsreftest",
+                                                       "tests", "user.js"))
 
         self.log_manager.enable_unstructured()
         try:
             rv = runreftest.run_test_harness(parser, args)
         finally:
             self.log_manager.disable_unstructured()
 
         return rv
--- a/layout/tools/reftest/output.py
+++ b/layout/tools/reftest/output.py
@@ -1,14 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import json
-import os
 import threading
 
 from mozlog.formatters import TbplFormatter
 from mozrunner.utils import get_stack_fixer_function
 
 
 class ReftestFormatter(TbplFormatter):
     """
@@ -44,28 +43,28 @@ class ReftestFormatter(TbplFormatter):
             status_msg += "UNEXPECTED-%s" % status
         else:
             if status != "PASS":
                 status_msg += "KNOWN-"
             status_msg += status
             if extra.get('status_msg') == 'Random':
                 status_msg += "(EXPECTED RANDOM)"
 
-
         output_text = "%s | %s | %s" % (status_msg, test, data.get("message", ""))
-
         if "reftest_screenshots" in extra:
             screenshots = extra["reftest_screenshots"]
+            image_1 = screenshots[0]["screenshot"]
+            image_2 = screenshots[2]["screenshot"]
+
             if len(screenshots) == 3:
                 output_text += ("\nREFTEST   IMAGE 1 (TEST): data:image/png;base64,%s\n"
-                                "REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,%s") % (screenshots[0]["screenshot"],
-                                                                         screenshots[2]["screenshot"])
+                                "REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,%s") % (
+                                image_1, image_2)
             elif len(screenshots) == 1:
-                output_text += "\nREFTEST   IMAGE: data:image/png;base64,%(image1)s" % screenshots[0]["screenshot"]
-
+                output_text += "\nREFTEST   IMAGE: data:image/png;base64,%(image1)s" % image_1
 
         output_text += "\nREFTEST TEST-END | %s" % test
         return "%s\n" % output_text
 
     def process_output(self, data):
         return "%s\n" % data["data"]
 
     def suite_end(self, data):
--- a/layout/tools/reftest/reftest/__init__.py
+++ b/layout/tools/reftest/reftest/__init__.py
@@ -29,16 +29,17 @@ FAILURE_TYPES = (
     'asserts-if',
 )
 PREF_ITEMS = (
     'pref',
     'test-pref',
     'ref-pref',
 )
 
+
 class ReftestManifest(object):
     """Represents a parsed reftest manifest.
 
     We currently only capture file information because that is the only thing
     tools require.
     """
     def __init__(self, finder=None):
         self.path = None
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -1,14 +1,13 @@
 import argparse
 import os
-import sys
 from collections import OrderedDict
 from urlparse import urlparse
-
+import mozinfo
 import mozlog
 
 here = os.path.abspath(os.path.dirname(__file__))
 
 
 class ReftestArgumentsParser(argparse.ArgumentParser):
     def __init__(self, **kwargs):
         super(ReftestArgumentsParser, self).__init__(**kwargs)
@@ -30,17 +29,18 @@ class ReftestArgumentsParser(argparse.Ar
                           default=None,
                           help="absolute path to directory containing XRE (probably xulrunner)")
 
         self.add_argument("--symbols-path",
                           action="store",
                           type=str,
                           dest="symbolsPath",
                           default=None,
-                          help="absolute path to directory containing breakpad symbols, or the URL of a zip file containing symbols")
+                          help="absolute path to directory containing breakpad symbols, "
+                               "or the URL of a zip file containing symbols")
 
         self.add_argument("--debugger",
                           action="store",
                           dest="debugger",
                           help="use the given debugger to launch the application")
 
         self.add_argument("--debugger-args",
                           action="store",
@@ -67,17 +67,18 @@ class ReftestArgumentsParser(argparse.Ar
                           default=[],
                           help="copy specified files/dirs to testing profile")
 
         self.add_argument("--timeout",
                           action="store",
                           dest="timeout",
                           type=int,
                           default=5 * 60,  # 5 minutes per bug 479518
-                          help="reftest will timeout in specified number of seconds. [default %(default)s].")
+                          help="reftest will timeout in specified number of seconds. "
+                               "[default %(default)s].")
 
         self.add_argument("--leak-threshold",
                           action="store",
                           type=int,
                           dest="defaultLeakThreshold",
                           default=0,
                           help="fail if the number of bytes leaked in default "
                           "processes through refcounted objects (or bytes "
@@ -114,17 +115,18 @@ class ReftestArgumentsParser(argparse.Ar
                           action="store_true",
                           default=False,
                           help="skip tests marked as slow when running")
 
         self.add_argument("--ignore-window-size",
                           dest="ignoreWindowSize",
                           action="store_true",
                           default=False,
-                          help="ignore the window size, which may cause spurious failures and passes")
+                          help="ignore the window size, which may cause spurious "
+                               "failures and passes")
 
         self.add_argument("--install-extension",
                           action="append",
                           dest="extensionsToInstall",
                           default=[],
                           help="install the specified extension in the testing profile. "
                           "The extension file's name should be <id>.xpi where <id> is "
                           "the extension's id as indicated in its install.rdf. "
@@ -213,20 +215,20 @@ class ReftestArgumentsParser(argparse.Ar
                           help="Path to the special powers extension")
 
         self.add_argument("--suite",
                           choices=["reftest", "crashtest", "jstestbrowser"],
                           default=None,
                           help=argparse.SUPPRESS)
 
         self.add_argument("--cleanup-crashes",
-                          action = "store_true",
-                          dest = "cleanupCrashes",
-                          default = False,
-                          help = "Delete pending crash reports before running tests.")
+                          action="store_true",
+                          dest="cleanupCrashes",
+                          default=False,
+                          help="Delete pending crash reports before running tests.")
 
         self.add_argument("tests",
                           metavar="TEST_PATH",
                           nargs="*",
                           help="Path to test file, manifest file, or directory containing tests")
 
         mozlog.commandline.add_logging_group(self)
 
@@ -255,17 +257,18 @@ class ReftestArgumentsParser(argparse.Ar
                     options.suite = suite
                     return
 
         self.error("Failed to determine test suite; supply --suite to set this explicitly")
 
     def validate(self, options, reftest):
         if not options.tests:
             # Can't just set this in the argument parser because mach will set a default
-            self.error("Must supply at least one path to a manifest file, test directory, or test file to run.")
+            self.error("Must supply at least one path to a manifest file, "
+                       "test directory, or test file to run.")
 
         if options.suite is None:
             self.set_default_suite(options)
 
         if options.totalChunks is not None and options.thisChunk is None:
             self.error(
                 "thisChunk must be specified when totalChunks is specified")
 
@@ -370,17 +373,19 @@ class RemoteArgumentsParser(ReftestArgum
                           xrePath="",
                           utilityPath="",
                           localLogName=None)
 
         self.add_argument("--remote-app-path",
                           action="store",
                           type=str,
                           dest="remoteAppPath",
-                          help="Path to remote executable relative to device root using only forward slashes.  Either this or app must be specified, but not both.")
+                          help="Path to remote executable relative to device root using only "
+                               "forward slashes.  Either this or app must be specified, "
+                               "but not both.")
 
         self.add_argument("--adbpath",
                           action="store",
                           type=str,
                           dest="adb_path",
                           default="adb",
                           help="path to adb")
 
@@ -403,17 +408,18 @@ class RemoteArgumentsParser(ReftestArgum
                           dest="devicePort",
                           help="port of remote device to test")
 
         self.add_argument("--remote-product-name",
                           action="store",
                           type=str,
                           dest="remoteProductName",
                           default="fennec",
-                          help="Name of product to test - either fennec or firefox, defaults to fennec")
+                          help="Name of product to test - either fennec or firefox, "
+                               "defaults to fennec")
 
         self.add_argument("--remote-webserver",
                           action="store",
                           type=str,
                           dest="remoteWebServer",
                           help="IP Address of the webserver hosting the reftest content")
 
         self.add_argument("--http-port",
@@ -428,37 +434,40 @@ class RemoteArgumentsParser(ReftestArgum
                           dest="sslPort",
                           help="Port for https traffic to the web server")
 
         self.add_argument("--remote-logfile",
                           action="store",
                           type=str,
                           dest="remoteLogFile",
                           default="reftest.log",
-                          help="Name of log file on the device relative to device root.  PLEASE USE ONLY A FILENAME.")
+                          help="Name of log file on the device relative to device root.  "
+                               "PLEASE USE ONLY A FILENAME.")
 
         self.add_argument("--pidfile",
                           action="store",
                           type=str,
                           dest="pidFile",
                           default="",
                           help="name of the pidfile to generate")
 
         self.add_argument("--dm_trans",
                           action="store",
                           type=str,
                           dest="dm_trans",
                           default="sut",
-                          help="the transport to use to communicate with device: [adb|sut]; default=sut")
+                          help="the transport to use to communicate with device: "
+                               "[adb|sut]; default=sut")
 
         self.add_argument("--remoteTestRoot",
                           action="store",
                           type=str,
                           dest="remoteTestRoot",
-                          help="remote directory to use as test root (eg. /mnt/sdcard/tests or /data/local/tests)")
+                          help="remote directory to use as test root "
+                               "(eg. /mnt/sdcard/tests or /data/local/tests)")
 
         self.add_argument("--httpd-path",
                           action="store",
                           type=str,
                           dest="httpdPath",
                           help="path to the httpd.js file")
 
         self.add_argument("--no-device-info",
@@ -475,17 +484,18 @@ class RemoteArgumentsParser(ReftestArgum
         options.remoteProfile = options.remoteTestRoot + "/profile"
 
         if options.remoteWebServer is None:
             options.remoteWebServer = self.get_ip()
 
         # Verify that our remotewebserver is set properly
         if options.remoteWebServer == '127.0.0.1':
             self.error("ERROR: Either you specified the loopback for the remote webserver or ",
-                       "your local IP cannot be detected.  Please provide the local ip in --remote-webserver")
+                       "your local IP cannot be detected.  "
+                       "Please provide the local ip in --remote-webserver")
 
         if not options.httpPort:
             options.httpPort = automation.DEFAULT_HTTP_PORT
 
         if not options.sslPort:
             options.sslPort = automation.DEFAULT_SSL_PORT
 
         # One of remoteAppPath (relative path to application) or the app (executable) must be
@@ -534,15 +544,16 @@ class RemoteArgumentsParser(ReftestArgum
             options.httpdPath = os.path.join(options.utilityPath, "components")
 
         if not options.ignoreWindowSize:
             parts = automation._devicemanager.getInfo(
                 'screen')['screen'][0].split()
             width = int(parts[0].split(':')[1])
             height = int(parts[1].split(':')[1])
             if (width < 1366 or height < 1050):
-                self.error("ERROR: Invalid screen resolution %sx%s, please adjust to 1366x1050 or higher" % (
-                    width, height))
+                self.error("ERROR: Invalid screen resolution %sx%s, "
+                           "please adjust to 1366x1050 or higher" % (
+                            width, height))
 
         # Disable e10s by default on Android because we don't run Android
         # e10s jobs anywhere yet.
         options.e10s = False
         return options
--- a/layout/tools/reftest/remotereftest.py
+++ b/layout/tools/reftest/remotereftest.py
@@ -30,18 +30,18 @@ class RemoteReftestResolver(ReftestResol
         elif os.path.exists(os.path.abspath(path)):
             rv = os.path.abspath(path)
         else:
             print >> sys.stderr, "Could not find manifest %s" % script_abs_path
             sys.exit(1)
         return os.path.normpath(rv)
 
     def manifestURL(self, options, path):
-        # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside' the webroot
-        # It's possible for this url to have a leading "..", but reftest.js will fix that up
+        # Dynamically build the reftest URL if possible, beware that args[0] should exist 'inside'
+        # webroot. It's possible for this url to have a leading "..", but reftest.js will fix that
         relPath = os.path.relpath(path, SCRIPT_DIRECTORY)
         return "http://%s:%s/%s" % (options.remoteWebServer, options.httpPort, relPath)
 
 
 class ReftestServer:
     """ Web server used to serve Reftests, for closer fidelity to the real web.
         It is virtually identical to the server used in mochitest and will only
         be used for running reftests remotely.
@@ -53,44 +53,47 @@ class ReftestServer:
         self._utilityPath = options.utilityPath
         self._xrePath = options.xrePath
         self._profileDir = options.serverProfilePath
         self.webServer = options.remoteWebServer
         self.httpPort = options.httpPort
         self.scriptDir = scriptDir
         self.pidFile = options.pidFile
         self._httpdPath = os.path.abspath(options.httpdPath)
-        self.shutdownURL = "http://%(server)s:%(port)s/server/shutdown" % { "server" : self.webServer, "port" : self.httpPort }
+        self.shutdownURL = "http://%(server)s:%(port)s/server/shutdown" % {
+                           "server": self.webServer, "port": self.httpPort}
 
     def start(self):
         "Run the Refest server, returning the process ID of the server."
 
-        env = self.automation.environment(xrePath = self._xrePath)
+        env = self.automation.environment(xrePath=self._xrePath)
         env["XPCOM_DEBUG_BREAK"] = "warn"
         if self.automation.IS_WIN32:
             env["PATH"] = env["PATH"] + ";" + self._xrePath
 
         args = ["-g", self._xrePath,
                 "-v", "170",
                 "-f", os.path.join(self._httpdPath, "httpd.js"),
-                "-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR ='%(server)s';" %
-                       {"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer },
+                "-e", "const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = "
+                      "'%(port)s'; const _SERVER_ADDR ='%(server)s';" % {
+                      "profile": self._profileDir.replace('\\', '\\\\'), "port": self.httpPort,
+                      "server": self.webServer},
                 "-f", os.path.join(self.scriptDir, "server.js")]
 
         xpcshell = os.path.join(self._utilityPath,
                                 "xpcshell" + self.automation.BIN_SUFFIX)
 
         if not os.access(xpcshell, os.F_OK):
             raise Exception('xpcshell not found at %s' % xpcshell)
         if self.automation.elf_arm(xpcshell):
             raise Exception('xpcshell at %s is an ARM binary; please use '
                             'the --utility-path argument to specify the path '
                             'to a desktop version.' % xpcshell)
 
-        self._process = self.automation.Process([xpcshell] + args, env = env)
+        self._process = self.automation.Process([xpcshell] + args, env=env)
         pid = self._process.pid
         if pid < 0:
             print "TEST-UNEXPECTED-FAIL | remotereftests.py | Error starting server."
             return 2
         self.automation.log.info("INFO | remotereftests.py | Server pid: %d", pid)
 
         if (self.pidFile != ""):
             f = open(self.pidFile + ".xpcshell.pid", 'w')
@@ -103,33 +106,35 @@ class ReftestServer:
         aliveFile = os.path.join(self._profileDir, "server_alive.txt")
         i = 0
         while i < timeout:
             if os.path.exists(aliveFile):
                 break
             time.sleep(1)
             i += 1
         else:
-            print "TEST-UNEXPECTED-FAIL | remotereftests.py | Timed out while waiting for server startup."
+            print ("TEST-UNEXPECTED-FAIL | remotereftests.py | "
+                   "Timed out while waiting for server startup.")
             self.stop()
             return 1
 
     def stop(self):
         if hasattr(self, '_process'):
             try:
                 c = urllib2.urlopen(self.shutdownURL)
                 c.read()
                 c.close()
 
                 rtncode = self._process.poll()
-                if (rtncode == None):
+                if (rtncode is None):
                     self._process.terminate()
             except:
                 self._process.kill()
 
+
 class RemoteReftest(RefTest):
     use_marionette = False
     remoteApp = ''
     resolver_cls = RemoteReftestResolver
 
     def __init__(self, automation, devicemanager, options, scriptDir):
         RefTest.__init__(self)
         self.automation = automation
@@ -150,17 +155,17 @@ class RemoteReftest(RefTest):
 
         self._populate_logger(options)
         outputHandler = OutputHandler(self.log, options.utilityPath, options.symbolsPath)
         # RemoteAutomation.py's 'messageLogger' is also used by mochitest. Mimic a mochitest
         # MessageLogger object to re-use this code path.
         outputHandler.write = outputHandler.__call__
         self.automation._processArgs['messageLogger'] = outputHandler
 
-    def findPath(self, paths, filename = None):
+    def findPath(self, paths, filename=None):
         for path in paths:
             p = path
             if filename:
                 p = os.path.join(p, filename)
             if os.path.exists(self.getFullPath(p)):
                 return path
         return None
 
@@ -169,42 +174,45 @@ class RemoteReftest(RefTest):
         remoteXrePath = options.xrePath
         remoteUtilityPath = options.utilityPath
         localAutomation = Automation()
         localAutomation.IS_WIN32 = False
         localAutomation.IS_LINUX = False
         localAutomation.IS_MAC = False
         localAutomation.UNIXISH = False
         hostos = sys.platform
-        if (hostos == 'mac' or  hostos == 'darwin'):
+        if (hostos == 'mac' or hostos == 'darwin'):
             localAutomation.IS_MAC = True
         elif (hostos == 'linux' or hostos == 'linux2'):
             localAutomation.IS_LINUX = True
             localAutomation.UNIXISH = True
         elif (hostos == 'win32' or hostos == 'win64'):
             localAutomation.BIN_SUFFIX = ".exe"
             localAutomation.IS_WIN32 = True
 
-        paths = [options.xrePath, localAutomation.DIST_BIN, self.automation._product, os.path.join('..', self.automation._product)]
+        paths = [options.xrePath, localAutomation.DIST_BIN, self.automation._product,
+                 os.path.join('..', self.automation._product)]
         options.xrePath = self.findPath(paths)
-        if options.xrePath == None:
-            print "ERROR: unable to find xulrunner path for %s, please specify with --xre-path" % (os.name)
+        if options.xrePath is None:
+            print ("ERROR: unable to find xulrunner path for %s, "
+                   "please specify with --xre-path" % (os.name))
             return 1
         paths.append("bin")
         paths.append(os.path.join("..", "bin"))
 
         xpcshell = "xpcshell"
         if (os.name == "nt"):
             xpcshell += ".exe"
 
         if (options.utilityPath):
             paths.insert(0, options.utilityPath)
         options.utilityPath = self.findPath(paths, xpcshell)
-        if options.utilityPath == None:
-            print "ERROR: unable to find utility path for %s, please specify with --utility-path" % (os.name)
+        if options.utilityPath is None:
+            print ("ERROR: unable to find utility path for %s, "
+                   "please specify with --utility-path" % (os.name))
             return 1
 
         options.serverProfilePath = tempfile.mkdtemp()
         self.server = ReftestServer(localAutomation, options, self.scriptDir)
         retVal = self.server.start()
         if retVal:
             return retVal
         retVal = self.server.ensureReady(self.SERVER_STARTUP_TIMEOUT)
@@ -313,22 +321,24 @@ class RemoteReftest(RefTest):
         self._devicemanager.removeDir(self.remoteProfile)
         self._devicemanager.removeDir(self.remoteTestRoot)
         RefTest.cleanup(self, profileDir)
         if (self.pidFile != ""):
             try:
                 os.remove(self.pidFile)
                 os.remove(self.pidFile + ".xpcshell.pid")
             except:
-                print "Warning: cleaning up pidfile '%s' was unsuccessful from the test harness" % self.pidFile
+                print ("Warning: cleaning up pidfile '%s' was unsuccessful "
+                       "from the test harness" % self.pidFile)
 
 
 def run_test_harness(parser, options):
-    if options.dm_trans == 'sut' and options.deviceIP == None:
-        print "Error: If --dm_trans = sut, you must provide a device IP to connect to via the --deviceIP option"
+    if options.dm_trans == 'sut' and options.deviceIP is None:
+        print ("Error: If --dm_trans = sut, you must provide a device IP to "
+               "connect to via the --deviceIP option")
         return 1
 
     dm_args = {
         'deviceRoot': options.remoteTestRoot,
         'host': options.deviceIP,
         'port': options.devicePort,
     }
 
@@ -338,17 +348,18 @@ def run_test_harness(parser, options):
         if not dm_args['host']:
             dm_args['deviceSerial'] = options.deviceSerial
         dm_cls = mozdevice.DroidADB
 
     try:
         dm = dm_cls(**dm_args)
     except mozdevice.DMError:
         traceback.print_exc()
-        print "Automation Error: exception while initializing devicemanager.  Most likely the device is not in a testable state."
+        print ("Automation Error: exception while initializing devicemanager.  "
+               "Most likely the device is not in a testable state.")
         return 1
 
     automation = RemoteAutomation(None)
     automation.setDeviceManager(dm)
 
     if options.remoteProductName:
         automation.setProduct(options.remoteProductName)
 
@@ -382,18 +393,19 @@ def run_test_harness(parser, options):
 
     procName = options.app.split('/')[-1]
     if (dm.processExist(procName)):
         dm.killProcess(procName)
 
     if options.printDeviceInfo:
         reftest.printDeviceInfo()
 
-#an example manifest name to use on the cli
-#    manifest = "http://" + options.remoteWebServer + "/reftests/layout/reftests/reftest-sanity/reftest.list"
+# an example manifest name to use on the cli
+# manifest = "http://" + options.remoteWebServer +
+# "/reftests/layout/reftests/reftest-sanity/reftest.list"
     retVal = 0
     try:
         dm.recordLogcat()
         retVal = reftest.runTests(options.tests, options)
     except:
         print "Automation Error: Exception caught while running tests"
         traceback.print_exc()
         retVal = 1
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -128,16 +128,17 @@ class ReftestThread(threading.Thread):
                     haveSuppressedSummaryLine = True
                     break
             if haveSuppressedSummaryLine:
                 continue
 
             if summaryHeadRegex.search(line) is None:
                 yield line
 
+
 class ReftestResolver(object):
     def defaultManifest(self, suite):
         return {"reftest": "reftest.list",
                 "crashtest": "crashtests.list",
                 "jstestbrowser": "jstests.list"}[suite]
 
     def directoryManifest(self, suite, path):
         return os.path.join(path, self.defaultManifest(suite))
@@ -310,17 +311,18 @@ class RefTest(object):
         if not self.use_marionette:
             addons.append(options.reftestExtensionPath)
 
         if options.specialPowersExtensionPath is not None:
             if not self.use_marionette:
                 addons.append(options.specialPowersExtensionPath)
             # SpecialPowers requires insecure automation-only features that we
             # put behind a pref.
-            prefs['security.turn_off_all_security_so_that_viruses_can_take_over_this_computer'] = True
+            prefs['security.turn_off_all_security_so_that_viruses'
+                  '_can_take_over_this_computer'] = True
 
         for pref in prefs:
             prefs[pref] = mozprofile.Preferences.cast(prefs[pref])
 
         # Install distributed extensions, if application has any.
         distExtDir = os.path.join(options.app[:options.app.rfind(os.sep)],
                                   "distribution", "extensions")
         if os.path.isdir(distExtDir):
@@ -506,18 +508,19 @@ class RefTest(object):
             print 'REFTEST INFO | ' + text + ': ' + str(summaryObj['total']) + ' (' + details + ')'
 
         return int(any(t.retcode != 0 for t in threads))
 
     def handleTimeout(self, timeout, proc, utilityPath, debuggerInfo):
         """handle process output timeout"""
         # TODO: bug 913975 : _processOutput should call self.processOutputLine
         # one more time one timeout (I think)
-        self.log.error("%s | application timed out after %d seconds with no output" % (self.lastTestSeen, int(timeout)))
-        self.log.error("Force-terminating active process(es).");
+        self.log.error("%s | application timed out after %d seconds with no output" % (
+                       self.lastTestSeen, int(timeout)))
+        self.log.error("Force-terminating active process(es).")
         self.killAndGetStack(
             proc, utilityPath, debuggerInfo, dump_screen=not debuggerInfo)
 
     def dumpScreen(self, utilityPath):
         if self.haveDumpedScreen:
             self.log.info("Not taking screenshot here: see the one that was previously logged")
             return
         self.haveDumpedScreen = True
@@ -677,18 +680,17 @@ class RefTest(object):
                                  timeout=options.timeout + 30.0,
                                  symbolsPath=options.symbolsPath,
                                  options=options,
                                  debuggerInfo=debuggerInfo)
             self.log.info("Process mode: {}".format('e10s' if options.e10s else 'non-e10s'))
             mozleak.process_leak_log(self.leakLogFile,
                                      leak_thresholds=options.leakThresholds,
                                      stack_fixer=get_stack_fixer_function(options.utilityPath,
-                                                                          options.symbolsPath),
-            )
+                                                                          options.symbolsPath))
         finally:
             self.cleanup(profileDir)
         return status
 
     def copyExtraFilesToProfile(self, options, profile):
         "Copy extra files or dirs specified on the command line to the testing profile."
         profileDir = profile.profile
         if not os.path.exists(os.path.join(profileDir, "hyphenation")):
--- a/media/libogg/CHANGES
+++ b/media/libogg/CHANGES
@@ -1,8 +1,19 @@
+Version 1.3.2 (2014 May 27)
+
+ * Fix an bug in oggpack_writecopy().
+
+Version 1.3.1 (2013 May 12)
+
+* Guard against very large packets.
+* Respect the configure --docdir override.
+* Documentation fixes.
+* More Windows build fixes.
+
 Version 1.3.0 (2011 August 4)
 
 * Add ogg_stream_flush_fill() call
   This produces longer packets on flush, similar to
   what ogg_stream_pageout_fill() does for single pages.
 * Windows build fixes
 
 Version 1.2.2 (2010 December 07)
--- a/media/libogg/README_MOZILLA
+++ b/media/libogg/README_MOZILLA
@@ -1,8 +1,8 @@
-The source from this directory was copied from the libogg subversion
-repository using the update.sh script.
+Version: 1.3.2
 
-The svn revision number used was r17287.
+The source from this directory was extracted from the official source
+package downloaded from xiph.org and copied using the update.sh script.
 
 The int-types.patch address a bug that config_types.h generated from
 Linux platform can't be used on OpenSolaris directly see Mozilla bug
 449754
--- a/media/libogg/include/ogg/os_types.h
+++ b/media/libogg/include/ogg/os_types.h
@@ -6,17 +6,17 @@
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
  * by the Xiph.Org Foundation http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
  function: #ifdef jail to whip a few platforms into the UNIX ideal.
- last mod: $Id: os_types.h 17712 2010-12-03 17:10:02Z xiphmont $
+ last mod: $Id: os_types.h 19098 2014-02-26 19:06:45Z giles $
 
  ********************************************************************/
 #ifndef _OS_TYPES_H
 #define _OS_TYPES_H
 
 #include <stddef.h>
 
 /* We indirect mallocs through settable-at-runtime functions to accommodate
@@ -40,17 +40,17 @@ extern ogg_free_function_type *ogg_free_
 }
 #endif
 
 #define _ogg_malloc ogg_malloc_func
 #define _ogg_calloc ogg_calloc_func
 #define _ogg_realloc ogg_realloc_func
 #define _ogg_free ogg_free_func
 
-#if defined(_WIN32) 
+#if defined(_WIN32)
 
 #  if defined(__CYGWIN__)
 #    include <stdint.h>
      typedef int16_t ogg_int16_t;
      typedef uint16_t ogg_uint16_t;
      typedef int32_t ogg_int32_t;
      typedef uint32_t ogg_uint32_t;
      typedef int64_t ogg_int64_t;
--- a/media/libogg/src/ogg_bitwise.c
+++ b/media/libogg/src/ogg_bitwise.c
@@ -1,22 +1,22 @@
 /********************************************************************
  *                                                                  *
  * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE.              *
  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010             *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014             *
  * by the Xiph.Org Foundation http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
   function: packing variable sized words into an octet stream
-  last mod: $Id: bitwise.c 18051 2011-08-04 17:56:39Z giles $
+  last mod: $Id: bitwise.c 19149 2014-05-27 16:26:23Z giles $
 
  ********************************************************************/
 
 /* We're 'LSb' endian; if we write a word but read individual bits,
    then we'll read the lsb first */
 
 #include <string.h>
 #include <stdlib.h>
@@ -182,42 +182,46 @@ static void oggpack_writecopy_helper(ogg
                                      long bits,
                                      void (*w)(oggpack_buffer *,
                                                unsigned long,
                                                int),
                                      int msb){
   unsigned char *ptr=(unsigned char *)source;
 
   long bytes=bits/8;
+  long pbytes=(b->endbit+bits)/8;
   bits-=bytes*8;
 
+  /* expand storage up-front */
+  if(b->endbyte+pbytes>=b->storage){
+    void *ret;
+    if(!b->ptr) goto err;
+    if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err;
+    b->storage=b->endbyte+pbytes+BUFFER_INCREMENT;
+    ret=_ogg_realloc(b->buffer,b->storage);
+    if(!ret) goto err;
+    b->buffer=ret;
+    b->ptr=b->buffer+b->endbyte;
+  }
+
+  /* copy whole octets */
   if(b->endbit){
     int i;
     /* unaligned copy.  Do it the hard way. */
     for(i=0;i<bytes;i++)
       w(b,(unsigned long)(ptr[i]),8);
   }else{
     /* aligned block copy */
-    if(b->endbyte+bytes+1>=b->storage){
-      void *ret;
-      if(!b->ptr) goto err;
-      if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err;
-      b->storage=b->endbyte+bytes+BUFFER_INCREMENT;
-      ret=_ogg_realloc(b->buffer,b->storage);
-      if(!ret) goto err;
-      b->buffer=ret;
-      b->ptr=b->buffer+b->endbyte;
-    }
-
     memmove(b->ptr,source,bytes);
     b->ptr+=bytes;
     b->endbyte+=bytes;
     *b->ptr=0;
+  }
 
-  }
+  /* copy trailing bits */
   if(bits){
     if(msb)
       w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
     else
       w(b,(unsigned long)(ptr[bytes]),bits);
   }
   return;
  err:
@@ -608,19 +612,200 @@ void cliptestB(unsigned long *b,int vals
     }else{
     if(oggpackB_read(&r,tbit)!=(b[i]&mask[tbit]))
       report("read incorrect value!\n");
     }
   }
   if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
 }
 
+void copytest(int prefill, int copy){
+  oggpack_buffer source_write;
+  oggpack_buffer dest_write;
+  oggpack_buffer source_read;
+  oggpack_buffer dest_read;
+  unsigned char *source;
+  unsigned char *dest;
+  long source_bytes,dest_bytes;
+  int i;
+
+  oggpack_writeinit(&source_write);
+  oggpack_writeinit(&dest_write);
+
+  for(i=0;i<(prefill+copy+7)/8;i++)
+    oggpack_write(&source_write,(i^0x5a)&0xff,8);
+  source=oggpack_get_buffer(&source_write);
+  source_bytes=oggpack_bytes(&source_write);
+
+  /* prefill */
+  oggpack_writecopy(&dest_write,source,prefill);
+
+  /* check buffers; verify end byte masking */
+  dest=oggpack_get_buffer(&dest_write);
+  dest_bytes=oggpack_bytes(&dest_write);
+  if(dest_bytes!=(prefill+7)/8){
+    fprintf(stderr,"wrong number of bytes after prefill! %ld!=%d\n",dest_bytes,(prefill+7)/8);
+    exit(1);
+  }
+  oggpack_readinit(&source_read,source,source_bytes);
+  oggpack_readinit(&dest_read,dest,dest_bytes);
+
+  for(i=0;i<prefill;i+=8){
+    int s=oggpack_read(&source_read,prefill-i<8?prefill-i:8);
+    int d=oggpack_read(&dest_read,prefill-i<8?prefill-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+      exit(1);
+    }
+  }
+  if(prefill<dest_bytes){
+    if(oggpack_read(&dest_read,dest_bytes-prefill)!=0){
+      fprintf(stderr,"prefill=%d mismatch! trailing bits not zero\n",prefill);
+      exit(1);
+    }
+  }
+
+  /* second copy */
+  oggpack_writecopy(&dest_write,source,copy);
+
+  /* check buffers; verify end byte masking */
+  dest=oggpack_get_buffer(&dest_write);
+  dest_bytes=oggpack_bytes(&dest_write);
+  if(dest_bytes!=(copy+prefill+7)/8){
+    fprintf(stderr,"wrong number of bytes after prefill+copy! %ld!=%d\n",dest_bytes,(copy+prefill+7)/8);
+    exit(1);
+  }
+  oggpack_readinit(&source_read,source,source_bytes);
+  oggpack_readinit(&dest_read,dest,dest_bytes);
+
+  for(i=0;i<prefill;i+=8){
+    int s=oggpack_read(&source_read,prefill-i<8?prefill-i:8);
+    int d=oggpack_read(&dest_read,prefill-i<8?prefill-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+      exit(1);
+    }
+  }
+
+  oggpack_readinit(&source_read,source,source_bytes);
+  for(i=0;i<copy;i+=8){
+    int s=oggpack_read(&source_read,copy-i<8?copy-i:8);
+    int d=oggpack_read(&dest_read,copy-i<8?copy-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d copy=%d mismatch! byte %d, %x!=%x\n",prefill,copy,i/8,s,d);
+      exit(1);
+    }
+  }
+
+  if(copy+prefill<dest_bytes){
+    if(oggpack_read(&dest_read,dest_bytes-copy-prefill)!=0){
+      fprintf(stderr,"prefill=%d copy=%d mismatch! trailing bits not zero\n",prefill,copy);
+      exit(1);
+    }
+  }
+
+  oggpack_writeclear(&source_write);
+  oggpack_writeclear(&dest_write);
+
+
+}
+
+void copytestB(int prefill, int copy){
+  oggpack_buffer source_write;
+  oggpack_buffer dest_write;
+  oggpack_buffer source_read;
+  oggpack_buffer dest_read;
+  unsigned char *source;
+  unsigned char *dest;
+  long source_bytes,dest_bytes;
+  int i;
+
+  oggpackB_writeinit(&source_write);
+  oggpackB_writeinit(&dest_write);
+
+  for(i=0;i<(prefill+copy+7)/8;i++)
+    oggpackB_write(&source_write,(i^0x5a)&0xff,8);
+  source=oggpackB_get_buffer(&source_write);
+  source_bytes=oggpackB_bytes(&source_write);
+
+  /* prefill */
+  oggpackB_writecopy(&dest_write,source,prefill);
+
+  /* check buffers; verify end byte masking */
+  dest=oggpackB_get_buffer(&dest_write);
+  dest_bytes=oggpackB_bytes(&dest_write);
+  if(dest_bytes!=(prefill+7)/8){
+    fprintf(stderr,"wrong number of bytes after prefill! %ld!=%d\n",dest_bytes,(prefill+7)/8);
+    exit(1);
+  }
+  oggpackB_readinit(&source_read,source,source_bytes);
+  oggpackB_readinit(&dest_read,dest,dest_bytes);
+
+  for(i=0;i<prefill;i+=8){
+    int s=oggpackB_read(&source_read,prefill-i<8?prefill-i:8);
+    int d=oggpackB_read(&dest_read,prefill-i<8?prefill-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+      exit(1);
+    }
+  }
+  if(prefill<dest_bytes){
+    if(oggpackB_read(&dest_read,dest_bytes-prefill)!=0){
+      fprintf(stderr,"prefill=%d mismatch! trailing bits not zero\n",prefill);
+      exit(1);
+    }
+  }
+
+  /* second copy */
+  oggpackB_writecopy(&dest_write,source,copy);
+
+  /* check buffers; verify end byte masking */
+  dest=oggpackB_get_buffer(&dest_write);
+  dest_bytes=oggpackB_bytes(&dest_write);
+  if(dest_bytes!=(copy+prefill+7)/8){
+    fprintf(stderr,"wrong number of bytes after prefill+copy! %ld!=%d\n",dest_bytes,(copy+prefill+7)/8);
+    exit(1);
+  }
+  oggpackB_readinit(&source_read,source,source_bytes);
+  oggpackB_readinit(&dest_read,dest,dest_bytes);
+
+  for(i=0;i<prefill;i+=8){
+    int s=oggpackB_read(&source_read,prefill-i<8?prefill-i:8);
+    int d=oggpackB_read(&dest_read,prefill-i<8?prefill-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d mismatch! byte %d, %x!=%x\n",prefill,i/8,s,d);
+      exit(1);
+    }
+  }
+
+  oggpackB_readinit(&source_read,source,source_bytes);
+  for(i=0;i<copy;i+=8){
+    int s=oggpackB_read(&source_read,copy-i<8?copy-i:8);
+    int d=oggpackB_read(&dest_read,copy-i<8?copy-i:8);
+    if(s!=d){
+      fprintf(stderr,"prefill=%d copy=%d mismatch! byte %d, %x!=%x\n",prefill,copy,i/8,s,d);
+      exit(1);
+    }
+  }
+
+  if(copy+prefill<dest_bytes){
+    if(oggpackB_read(&dest_read,dest_bytes-copy-prefill)!=0){
+      fprintf(stderr,"prefill=%d copy=%d mismatch! trailing bits not zero\n",prefill,copy);
+      exit(1);
+    }
+  }
+
+  oggpackB_writeclear(&source_write);
+  oggpackB_writeclear(&dest_write);
+
+}
+
 int main(void){
   unsigned char *buffer;
-  long bytes,i;
+  long bytes,i,j;
   static unsigned long testbuffer1[]=
     {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
        567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
   int test1size=43;
 
   static unsigned long testbuffer2[]=
     {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
        1233432,534,5,346435231,14436467,7869299,76326614,167548585,
@@ -756,17 +941,41 @@ int main(void){
       exit(1);
   }
   if(oggpack_look(&r,32)!=-1 ||
      oggpack_look(&r,32)!=-1){
     fprintf(stderr,"failed; read past end without -1.\n");
       exit(1);
   }
   oggpack_writeclear(&o);
-  fprintf(stderr,"ok.\n");
+  fprintf(stderr,"ok.");
+
+  /* this is partly glassbox; we're mostly concerned about the allocation boundaries */
+
+  fprintf(stderr,"\nTesting aligned writecopies (LSb): ");
+  for(i=0;i<71;i++)
+    for(j=0;j<5;j++)
+      copytest(j*8,i);
+  for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+    for(j=0;j<5;j++)
+      copytest(j*8,i);
+  fprintf(stderr,"ok.      ");
+
+  fprintf(stderr,"\nTesting unaligned writecopies (LSb): ");
+  for(i=0;i<71;i++)
+    for(j=1;j<40;j++)
+      if(j&0x7)
+        copytest(j,i);
+  for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+    for(j=1;j<40;j++)
+      if(j&0x7)
+        copytest(j,i);
+  
+  fprintf(stderr,"ok.      \n");
+
 
   /********** lazy, cut-n-paste retest with MSb packing ***********/
 
   /* Test read/write together */
   /* Later we test against pregenerated bitstreams */
   oggpackB_writeinit(&o);
 
   fprintf(stderr,"\nSmall preclipped packing (MSb): ");
@@ -841,17 +1050,39 @@ int main(void){
     fprintf(stderr,"failed; read past end without -1.\n");
       exit(1);
   }
   if(oggpackB_look(&r,32)!=-1 ||
      oggpackB_look(&r,32)!=-1){
     fprintf(stderr,"failed; read past end without -1.\n");
       exit(1);
   }
+  fprintf(stderr,"ok.");
   oggpackB_writeclear(&o);
-  fprintf(stderr,"ok.\n\n");
+
+  /* this is partly glassbox; we're mostly concerned about the allocation boundaries */
+
+  fprintf(stderr,"\nTesting aligned writecopies (MSb): ");
+  for(i=0;i<71;i++)
+    for(j=0;j<5;j++)
+      copytestB(j*8,i);
+  for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+    for(j=0;j<5;j++)
+      copytestB(j*8,i);
+  fprintf(stderr,"ok.      ");
 
+  fprintf(stderr,"\nTesting unaligned writecopies (MSb): ");
+  for(i=0;i<71;i++)
+    for(j=1;j<40;j++)
+      if(j&0x7)
+        copytestB(j,i);
+  for(i=BUFFER_INCREMENT*8-71;i<BUFFER_INCREMENT*8+71;i++)
+    for(j=1;j<40;j++)
+      if(j&0x7)
+        copytestB(j,i);
+  
+  fprintf(stderr,"ok.      \n\n");
 
   return(0);
 }
 #endif  /* _V_SELFTEST */
 
 #undef BUFFER_INCREMENT
--- a/media/libogg/src/ogg_framing.c
+++ b/media/libogg/src/ogg_framing.c
@@ -7,25 +7,26 @@
  *                                                                  *
  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010             *
  * by the Xiph.Org Foundation http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
  function: code raw packets into framed OggSquish stream and
            decode Ogg streams back into raw packets
- last mod: $Id: framing.c 18052 2011-08-04 17:57:02Z giles $
+ last mod: $Id: framing.c 18758 2013-01-08 16:29:56Z tterribe $
 
  note: The CRC code is directly derived from public domain code by
  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
  for details.
 
  ********************************************************************/
 
 #include <stdlib.h>
+#include <limits.h>
 #include <string.h>
 #include <ogg/ogg.h>
 
 /* A complete description of Ogg framing exists in docs/framing.html */
 
 int ogg_page_version(const ogg_page *og){
   return((int)(og->header[4]));
 }
@@ -231,49 +232,61 @@ int ogg_stream_destroy(ogg_stream_state 
     _ogg_free(os);
   }
   return(0);
 }
 
 /* Helpers for ogg_stream_encode; this keeps the structure and
    what's happening fairly clear */
 
-static int _os_body_expand(ogg_stream_state *os,int needed){
-  if(os->body_storage<=os->body_fill+needed){
+static int _os_body_expand(ogg_stream_state *os,long needed){
+  if(os->body_storage-needed<=os->body_fill){
+    long body_storage;
     void *ret;
-    ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
-                     sizeof(*os->body_data));
+    if(os->body_storage>LONG_MAX-needed){
+      ogg_stream_clear(os);
+      return -1;
+    }
+    body_storage=os->body_storage+needed;
+    if(body_storage<LONG_MAX-1024)body_storage+=1024;
+    ret=_ogg_realloc(os->body_data,body_storage*sizeof(*os->body_data));
     if(!ret){
       ogg_stream_clear(os);
       return -1;
     }
-    os->body_storage+=(needed+1024);
+    os->body_storage=body_storage;
     os->body_data=ret;
   }
   return 0;
 }
 
-static int _os_lacing_expand(ogg_stream_state *os,int needed){
-  if(os->lacing_storage<=os->lacing_fill+needed){
+static int _os_lacing_expand(ogg_stream_state *os,long needed){
+  if(os->lacing_storage-needed<=os->lacing_fill){
+    long lacing_storage;
     void *ret;
-    ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
-                     sizeof(*os->lacing_vals));
+    if(os->lacing_storage>LONG_MAX-needed){
+      ogg_stream_clear(os);
+      return -1;
+    }
+    lacing_storage=os->lacing_storage+needed;
+    if(lacing_storage<LONG_MAX-32)lacing_storage+=32;
+    ret=_ogg_realloc(os->lacing_vals,lacing_storage*sizeof(*os->lacing_vals));
     if(!ret){
       ogg_stream_clear(os);
       return -1;
     }
     os->lacing_vals=ret;
-    ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
+    ret=_ogg_realloc(os->granule_vals,lacing_storage*
                      sizeof(*os->granule_vals));
     if(!ret){
       ogg_stream_clear(os);
       return -1;
     }
     os->granule_vals=ret;
-    os->lacing_storage+=(needed+32);
+    os->lacing_storage=lacing_storage;
   }
   return 0;
 }
 
 /* checksum the page */
 /* Direct table CRC; note that this will be faster in the future if we
    perform the checksum simultaneously with other copies */
 
@@ -299,22 +312,27 @@ void ogg_page_checksum_set(ogg_page *og)
     og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
   }
 }
 
 /* submit data to the internal buffer of the framing engine */
 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
                        long e_o_s, ogg_int64_t granulepos){
 
-  int bytes = 0, lacing_vals, i;
+  long bytes = 0, lacing_vals;
+  int i;
 
   if(ogg_stream_check(os)) return -1;
   if(!iov) return 0;
 
-  for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
+  for (i = 0; i < count; ++i){
+    if(iov[i].iov_len>LONG_MAX) return -1;
+    if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1;
+    bytes += (long)iov[i].iov_len;
+  }
   lacing_vals=bytes/255+1;
 
   if(os->body_returned){
     /* advance packet data according to the body_returned pointer. We
        had to keep it around to return a pointer into the buffer last
        call */
 
     os->body_fill-=os->body_returned;
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1215,18 +1215,18 @@ public abstract class GeckoApp
             mIsRestoringActivity = true;
             Telemetry.addToHistogram("FENNEC_RESTORING_ACTIVITY", 1);
 
         } else {
             final String action = intent.getAction();
             final String args = intent.getStringExtra("args");
 
             sAlreadyLoaded = true;
-            GeckoThread.init(/* profile */ null, args, action,
-                             /* debugging */ ACTION_DEBUG.equals(action));
+            GeckoThread.initMainProcess(/* profile */ null, args,
+                                        /* debugging */ ACTION_DEBUG.equals(action));
 
             // Speculatively pre-fetch the profile in the background.
             ThreadUtils.postToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
                     getProfile();
                 }
             });
@@ -2388,17 +2388,18 @@ public abstract class GeckoApp
         }
 
         super.onDestroy();
 
         Tabs.unregisterOnTabsChangedListener(this);
     }
 
     public void showSDKVersionError() {
-        final String message = getString(R.string.unsupported_sdk_version, Build.CPU_ABI, Integer.toString(Build.VERSION.SDK_INT));
+        final String message = getString(R.string.unsupported_sdk_version,
+                HardwareUtils.getRealAbi(), Integer.toString(Build.VERSION.SDK_INT));
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
 
     // Get a temporary directory, may return null
     public static File getTempDirectory(@NonNull Context context) {
         return context.getApplicationContext().getExternalFilesDir("temp");
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoService.java
@@ -26,16 +26,18 @@ public class GeckoService extends Servic
     private static final String LOGTAG = "GeckoService";
     private static final boolean DEBUG = false;
 
     private static final String INTENT_PROFILE_NAME = "org.mozilla.gecko.intent.PROFILE_NAME";
     private static final String INTENT_PROFILE_DIR = "org.mozilla.gecko.intent.PROFILE_DIR";
 
     private static final String INTENT_ACTION_UPDATE_ADDONS = "update-addons";
     private static final String INTENT_ACTION_CREATE_SERVICES = "create-services";
+    private static final String INTENT_ACTION_LOAD_LIBS = "load-libs";
+    private static final String INTENT_ACTION_START_GECKO = "start-gecko";
 
     private static final String INTENT_SERVICE_CATEGORY = "category";
     private static final String INTENT_SERVICE_DATA = "data";
 
     private static class EventListener implements BundleEventListener {
         @Override // BundleEventListener
         public void handleMessage(final String event,
                                   final GeckoBundle message,
@@ -127,53 +129,78 @@ public class GeckoService extends Servic
         intent.putExtra(INTENT_SERVICE_DATA, data);
         return intent;
     }
 
     public static Intent getIntentToCreateServices(final Context context, final String category) {
         return getIntentToCreateServices(context, category, /* data */ null);
     }
 
+    public static Intent getIntentToLoadLibs(final Context context) {
+        return getIntentForAction(context, INTENT_ACTION_LOAD_LIBS);
+    }
+
+    public static Intent getIntentToStartGecko(final Context context) {
+        return getIntentForAction(context, INTENT_ACTION_START_GECKO);
+    }
+
     public static void setIntentProfile(final Intent intent, final String profileName,
                                         final String profileDir) {
         intent.putExtra(INTENT_PROFILE_NAME, profileName);
         intent.putExtra(INTENT_PROFILE_DIR, profileDir);
     }
 
-    private int handleIntent(final Intent intent, final int startId) {
-        if (DEBUG) {
-            Log.d(LOGTAG, "Handling " + intent.getAction());
+    private boolean initGecko(final Intent intent) {
+        if (INTENT_ACTION_LOAD_LIBS.equals(intent.getAction())) {
+            // Intentionally not initialize Gecko when only loading libs.
+            return true;
         }
 
         final String profileName = intent.getStringExtra(INTENT_PROFILE_NAME);
         final String profileDir = intent.getStringExtra(INTENT_PROFILE_DIR);
 
         if (profileName == null) {
             throw new IllegalArgumentException("Intent must specify profile.");
         }
 
-        if (!GeckoThread.initWithProfile(profileName, profileDir != null ? new File(profileDir) : null)) {
+        if (!GeckoThread.initMainProcessWithProfile(
+                profileName, profileDir != null ? new File(profileDir) : null)) {
             Log.w(LOGTAG, "Ignoring due to profile mismatch: " +
                           profileName + " [" + profileDir + ']');
 
             final GeckoProfile profile = GeckoThread.getActiveProfile();
             if (profile != null) {
                 Log.w(LOGTAG, "Current profile is " + profile.getName() +
                               " [" + profile.getDir().getAbsolutePath() + ']');
             }
+            return false;
+        }
+        return true;
+    }
+
+    private int handleIntent(final Intent intent, final int startId) {
+        if (DEBUG) {
+            Log.d(LOGTAG, "Handling " + intent.getAction());
+        }
+
+        if (!initGecko(intent)) {
             stopSelf(startId);
             return Service.START_NOT_STICKY;
         }
 
         GeckoThread.launch();
 
         switch (intent.getAction()) {
         case INTENT_ACTION_UPDATE_ADDONS:
             // Run the add-on update service. Because the service is automatically invoked
             // when loading Gecko, we don't have to do anything else here.
+        case INTENT_ACTION_LOAD_LIBS:
+            // Load libs only. Don't take any additional actions.
+        case INTENT_ACTION_START_GECKO:
+            // Load libs and start Gecko. Don't take any additional actions.
             break;
 
         case INTENT_ACTION_CREATE_SERVICES:
             final String category = intent.getStringExtra(INTENT_SERVICE_CATEGORY);
             final String data = intent.getStringExtra(INTENT_SERVICE_DATA);
 
             if (category == null) {
                 break;
@@ -201,35 +228,9 @@ public class GeckoService extends Servic
             return Service.START_NOT_STICKY;
         }
     }
 
     @Override // Service
     public IBinder onBind(final Intent intent) {
         return null;
     }
-
-    public static void startGecko(final GeckoProfile profile, final String args, final Context context) {
-        if (GeckoThread.isLaunched()) {
-            if (DEBUG) {
-                Log.v(LOGTAG, "already launched");
-            }
-            return;
-        }
-
-        Handler handler = new Handler(Looper.getMainLooper());
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                GeckoAppShell.ensureCrashHandling();
-                GeckoAppShell.setApplicationContext(context);
-                GeckoThread.onResume();
-
-                GeckoThread.init(profile, args, null, false);
-                GeckoThread.launch();
-
-                if (DEBUG) {
-                    Log.v(LOGTAG, "warmed up (launched)");
-                }
-            }
-        });
-    }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/PackageReplacedReceiver.java
+++ b/mobile/android/base/java/org/mozilla/gecko/PackageReplacedReceiver.java
@@ -3,36 +3,29 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
-import org.mozilla.gecko.mozglue.GeckoLoader;
+import org.mozilla.gecko.GeckoService;
 
 /**
  * This broadcast receiver receives ACTION_MY_PACKAGE_REPLACED broadcasts and
  * starts procedures that should run after the APK has been updated.
  */
 public class PackageReplacedReceiver extends BroadcastReceiver {
     public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
 
     @Override
     public void onReceive(Context context, Intent intent) {
         if (intent == null || !ACTION_MY_PACKAGE_REPLACED.equals(intent.getAction())) {
             // This is not the broadcast we are looking for.
             return;
         }
 
-        // Extract Gecko libs to allow them to be loaded from cache on startup.
-        extractGeckoLibs(context);
-    }
-
-    private static void extractGeckoLibs(final Context context) {
-        final String resourcePath = context.getPackageResourcePath();
-        GeckoLoader.loadMozGlue(context);
-        GeckoLoader.extractGeckoLibs(context, resourcePath);
+        // Load new Gecko libs to extract them to cache.
+        context.startService(GeckoService.getIntentToLoadLibs(context));
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/GeckoCustomTabsService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/GeckoCustomTabsService.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.customtabs;
 
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.customtabs.CustomTabsService;
 import android.support.customtabs.CustomTabsSessionToken;
 import android.util.Log;
 
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoService;
@@ -33,18 +34,25 @@ public class GeckoCustomTabsService exte
     }
 
     @Override
     protected boolean warmup(long flags) {
         if (DEBUG) {
             Log.v(LOGTAG, "warming up...");
         }
 
-        GeckoService.startGecko(GeckoProfile.initFromArgs(this, null), null, getApplicationContext());
+        if (GeckoThread.isRunning()) {
+            return true;
+        }
 
+        final Intent intent = GeckoService.getIntentToStartGecko(this);
+        // Use a default profile for warming up Gecko.
+        final GeckoProfile profile = GeckoProfile.get(this);
+        GeckoService.setIntentProfile(intent, profile.getName(), profile.getDir().getAbsolutePath());
+        startService(intent);
         return true;
     }
 
     @Override
     protected boolean newSession(CustomTabsSessionToken sessionToken) {
         Log.v(LOGTAG, "newSession()");
 
         // Pretend session has been started
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoProfile.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoProfile.java
@@ -78,17 +78,16 @@ public final class GeckoProfile {
 
     private static final ConcurrentHashMap<String, GeckoProfile> sProfileCache =
             new ConcurrentHashMap<String, GeckoProfile>(
                     /* capacity */ 4, /* load factor */ 0.75f, /* concurrency */ 2);
     private static String sDefaultProfileName;
 
     private final String mName;
     private final File mMozillaDir;
-    private final Context mApplicationContext;
 
     private Object mData;
 
     /**
      * Access to this member should be synchronized to avoid
      * races during creation -- particularly between getDir and GeckoView#init.
      *
      * Not final because this is lazily computed.
@@ -315,17 +314,16 @@ public final class GeckoProfile {
 
     private GeckoProfile(Context context, String profileName, File profileDir) throws NoMozillaDirectoryException {
         if (profileName == null) {
             throw new IllegalArgumentException("Unable to create GeckoProfile for empty profile name.");
         } else if (CUSTOM_PROFILE.equals(profileName) && profileDir == null) {
             throw new IllegalArgumentException("Custom profile must have a directory");
         }
 
-        mApplicationContext = context.getApplicationContext();
         mName = profileName;
         mMozillaDir = GeckoProfileDirectories.getMozillaDirectory(context);
 
         mProfileDir = profileDir;
         if (profileDir != null && !profileDir.isDirectory()) {
             throw new IllegalArgumentException("Profile directory must exist if specified.");
         }
     }
@@ -447,32 +445,32 @@ public final class GeckoProfile {
      * possible the format of this file (and the access calls in the jsm) will change, leaving
      * this code to fail. There are tests in TestGeckoProfile to verify the file format but be
      * warned: THIS IS NOT FOOLPROOF.
      *
      * [1]: https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/ClientID.jsm
      *
      * @throws IOException if the client ID could not be retrieved.
      */
-    // Mimics ClientID.jsm – _doLoadClientID.
+    // Mimics ClientID.jsm - _doLoadClientID.
     @WorkerThread
     public String getClientId() throws IOException {
         try {
             return getValidClientIdFromDisk(CLIENT_ID_FILE_PATH);
         } catch (final IOException e) {
             // Avoid log spam: don't log the full Exception w/ the stack trace.
             Log.d(LOGTAG, "Could not get client ID - attempting to migrate ID from FHR: " + e.getLocalizedMessage());
         }
 
         String clientIdToWrite;
         try {
             clientIdToWrite = getValidClientIdFromDisk(FHR_CLIENT_ID_FILE_PATH);
         } catch (final IOException e) {
             // Avoid log spam: don't log the full Exception w/ the stack trace.
-            Log.d(LOGTAG, "Could not migrate client ID from FHR – creating a new one: " + e.getLocalizedMessage());
+            Log.d(LOGTAG, "Could not migrate client ID from FHR - creating a new one: " + e.getLocalizedMessage());
             clientIdToWrite = generateNewClientId();
         }
 
         // There is a possibility Gecko is running and the Gecko telemetry implementation decided it's time to generate
         // the client ID, writing client ID underneath us. Since it's highly unlikely (e.g. we run in onStart before
         // Gecko is started), we don't handle that possibility besides writing the ID and then reading from the file
         // again (rather than just returning the value we generated before writing).
         //
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.mozglue.GeckoLoader;
+import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -20,16 +21,17 @@ import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 
 import java.io.File;
+import java.io.FilenameFilter;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Locale;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -118,62 +120,74 @@ public class GeckoThread extends Thread 
             ThreadUtils.assertOnUiThread();
             long nextDelay = runUiThreadCallback();
             if (nextDelay >= 0) {
                 ThreadUtils.getUiHandler().postDelayed(this, nextDelay);
             }
         }
     };
 
-    private static GeckoThread sGeckoThread;
+    private static final GeckoThread INSTANCE = new GeckoThread();
 
     @WrapForJNI
     private static final ClassLoader clsLoader = GeckoThread.class.getClassLoader();
     @WrapForJNI
     private static MessageQueue msgQueue;
 
-    private GeckoProfile mProfile;
+    private boolean mInitialized;
+    private String[] mArgs;
 
-    private final String mArgs;
-    private final String mAction;
-    private final boolean mDebugging;
+    // Main process parameters
+    private GeckoProfile mProfile;
+    private String mExtraArgs;
+    private boolean mDebugging;
 
-    private String[] mChildProcessArgs;
+    // Child process parameters
     private int mCrashFileDescriptor;
     private int mIPCFileDescriptor;
 
-    GeckoThread(GeckoProfile profile, String args, String action, boolean debugging) {
-        mProfile = profile;
-        mArgs = args;
-        mAction = action;
-        mDebugging = debugging;
-        mChildProcessArgs = null;
-        mCrashFileDescriptor = -1;
-        mIPCFileDescriptor = -1;
-
+    GeckoThread() {
         setName("Gecko");
     }
 
-    public static boolean init(GeckoProfile profile, String args, String action, boolean debugging) {
-        ThreadUtils.assertOnUiThread();
-        if (isState(State.INITIAL) && sGeckoThread == null) {
-            sGeckoThread = new GeckoThread(profile, args, action, debugging);
-            return true;
-        }
-        return false;
+    private boolean isChildProcess() {
+        return mIPCFileDescriptor != -1;
     }
 
-    public static boolean initChildProcess(GeckoProfile profile, String[] args, int crashFd, int ipcFd, boolean debugging) {
-        if (init(profile, null, null, debugging)) {
-            sGeckoThread.mChildProcessArgs = args;
-            sGeckoThread.mCrashFileDescriptor = crashFd;
-            sGeckoThread.mIPCFileDescriptor = ipcFd;
-            return true;
+    private synchronized boolean init(final GeckoProfile profile, final String[] args,
+                                      final String extraArgs, final boolean debugging,
+                                      final int crashFd, final int ipcFd) {
+        ThreadUtils.assertOnUiThread();
+
+        if (mInitialized) {
+            return false;
         }
-        return false;
+
+        mProfile = profile;
+        mArgs = args;
+        mExtraArgs = extraArgs;
+        mDebugging = debugging;
+        mCrashFileDescriptor = crashFd;
+        mIPCFileDescriptor = ipcFd;
+
+        mInitialized = true;
+        notifyAll();
+        return true;
+    }
+
+    public static boolean initMainProcess(final GeckoProfile profile, final String extraArgs,
+                                          final boolean debugging) {
+        return INSTANCE.init(profile, /* args */ null, extraArgs, debugging,
+                                 /* crashFd */ -1, /* ipcFd */ -1);
+    }
+
+    public static boolean initChildProcess(final String[] args, final int crashFd,
+                                           final int ipcFd) {
+        return INSTANCE.init(/* profile */ null, args, /* extraArgs */ null,
+                                 /* debugging */ false, crashFd, ipcFd);
     }
 
     private static boolean canUseProfile(final Context context, final GeckoProfile profile,
                                          final String profileName, final File profileDir) {
         if (profileDir != null && !profileDir.isDirectory()) {
             return false;
         }
 
@@ -196,17 +210,18 @@ public class GeckoThread extends Thread 
     public static boolean canUseProfile(final String profileName, final File profileDir) {
         if (profileName == null) {
             throw new IllegalArgumentException("Null profile name");
         }
         return canUseProfile(GeckoAppShell.getApplicationContext(), getActiveProfile(),
                              profileName, profileDir);
     }
 
-    public static boolean initWithProfile(final String profileName, final File profileDir) {
+    public static boolean initMainProcessWithProfile(final String profileName,
+                                                     final File profileDir) {
         if (profileName == null) {
             throw new IllegalArgumentException("Null profile name");
         }
 
         final Context context = GeckoAppShell.getApplicationContext();
         final GeckoProfile profile = getActiveProfile();
 
         if (!canUseProfile(context, profile, profileName, profileDir)) {
@@ -215,24 +230,25 @@ public class GeckoThread extends Thread 
         }
 
         if (profile != null) {
             // We already have a compatible profile.
             return true;
         }
 
         // We haven't initialized yet; okay to initialize now.
-        return init(GeckoProfile.get(context, profileName, profileDir),
-                    /* args */ null, /* action */ null, /* debugging */ false);
+        return initMainProcess(GeckoProfile.get(context, profileName, profileDir),
+                               /* args */ null, /* debugging */ false);
     }
 
     public static boolean launch() {
         ThreadUtils.assertOnUiThread();
+
         if (checkAndSetState(State.INITIAL, State.LAUNCHED)) {
-            sGeckoThread.start();
+            INSTANCE.start();
             return true;
         }
         return false;
     }
 
     public static boolean isLaunched() {
         return !isState(State.INITIAL);
     }
@@ -384,17 +400,23 @@ public class GeckoThread extends Thread 
             QUEUED_CALLS.trimToSize();
         } else if (lastSkipped < QUEUED_CALLS.size() - 1) {
             // We skipped some; free up null entries at the end,
             // but keep all the previous entries for later.
             QUEUED_CALLS.subList(lastSkipped + 1, QUEUED_CALLS.size()).clear();
         }
     }
 
-    private static String initGeckoEnvironment() {
+    private static void loadGeckoLibs(final Context context, final String resourcePath) {
+        GeckoLoader.loadSQLiteLibs(context, resourcePath);
+        GeckoLoader.loadNSSLibs(context, resourcePath);
+        GeckoLoader.loadGeckoLibs(context, resourcePath);
+    }
+
+    private static void initGeckoEnvironment() {
         final Context context = GeckoAppShell.getApplicationContext();
         GeckoLoader.loadMozGlue(context);
         setState(State.MOZGLUE_READY);
 
         final Locale locale = Locale.getDefault();
         final Resources res = context.getResources();
         if (locale.toString().equalsIgnoreCase("zh_hk")) {
             final Locale mappedLocale = Locale.TRADITIONAL_CHINESE;
@@ -409,93 +431,96 @@ public class GeckoThread extends Thread 
             pluginDirs = GeckoAppShell.getPluginDirectories();
         } catch (Exception e) {
             Log.w(LOGTAG, "Caught exception getting plugin dirs.", e);
         }
 
         final String resourcePath = context.getPackageResourcePath();
         GeckoLoader.setupGeckoEnvironment(context, pluginDirs, context.getFilesDir().getPath());
 
-        GeckoLoader.loadSQLiteLibs(context, resourcePath);
-        GeckoLoader.loadNSSLibs(context, resourcePath);
-        GeckoLoader.loadGeckoLibs(context, resourcePath);
+        try {
+            loadGeckoLibs(context, resourcePath);
+
+        } catch (final Exception e) {
+            // Cannot load libs; try clearing the cached files.
+            Log.w(LOGTAG, "Clearing cache after load libs exception", e);
+            FileUtils.delTree(GeckoLoader.getCacheDir(context),
+                              new FileUtils.FilenameRegexFilter(".*\\.so(?:\\.crc)?$"),
+                              /* recurse */ true);
+
+            // Then try loading again. If this throws again, we actually crash.
+            loadGeckoLibs(context, resourcePath);
+        }
+
         setState(State.LIBS_READY);
-
-        return resourcePath;
     }
 
-    private void addCustomProfileArg(String args, ArrayList<String> list) {
-        // Make sure a profile exists.
-        final GeckoProfile profile = getProfile();
-        profile.getDir(); // call the lazy initializer
+    private String[] getMainProcessArgs() {
+        final Context context = GeckoAppShell.getApplicationContext();
+        final ArrayList<String> args = new ArrayList<String>();
 
-        boolean needsProfile = true;
+        // argv[0] is the program name, which for us is the package name.
+        args.add(context.getPackageName());
+        args.add("-greomni");
+        args.add(context.getPackageResourcePath());
 
-        if (args != null) {
-            StringTokenizer st = new StringTokenizer(args);
-            while (st.hasMoreTokens()) {
-                String token = st.nextToken();
-                if ("-P".equals(token) || "-profile".equals(token)) {
-                    needsProfile = false;
-                }
-                list.add(token);
-            }
+        final GeckoProfile profile = getProfile();
+        if (profile.isCustomProfile()) {
+            args.add("-profile");
+            args.add(profile.getDir().getAbsolutePath());
+        } else {
+            profile.getDir(); // Make sure the profile dir exists.
+            args.add("-P");
+            args.add(profile.getName());
         }
 
-        // If args don't include the profile, make sure it's included.
-        if (args == null || needsProfile) {
-            if (profile.isCustomProfile()) {
-                list.add("-profile");
-                list.add(profile.getDir().getAbsolutePath());
-            } else {
-                list.add("-P");
-                list.add(profile.getName());
+        if (mExtraArgs != null) {
+            final StringTokenizer st = new StringTokenizer(mExtraArgs);
+            while (st.hasMoreTokens()) {
+                final String token = st.nextToken();
+                if ("-P".equals(token) || "-profile".equals(token)) {
+                    // Skip -P and -profile arguments because we added them above.
+                    if (st.hasMoreTokens()) {
+                        st.nextToken();
+                    }
+                    continue;
+                }
+                args.add(token);
             }
         }
-    }
-
-    private String[] getGeckoArgs(final String apkPath) {
-        // argv[0] is the program name, which for us is the package name.
-        final Context context = GeckoAppShell.getApplicationContext();
-        final ArrayList<String> args = new ArrayList<String>();
-        args.add(context.getPackageName());
-        args.add("-greomni");
-        args.add(apkPath);
-
-        addCustomProfileArg(mArgs, args);
 
         // In un-official builds, we want to load Javascript resources fresh
         // with each build.  In official builds, the startup cache is purged by
         // the buildid mechanism, but most un-official builds don't bump the
         // buildid, so we purge here instead.
         final GeckoAppShell.GeckoInterface gi = GeckoAppShell.getGeckoInterface();
         if (gi == null || !gi.isOfficial()) {
             Log.w(LOGTAG, "STARTUP PERFORMANCE WARNING: un-official build: purging the " +
                           "startup (JavaScript) caches.");
             args.add("-purgecaches");
         }
 
         return args.toArray(new String[args.size()]);
     }
 
     public static GeckoProfile getActiveProfile() {
-        if (sGeckoThread == null) {
-            return null;
-        }
-        final GeckoProfile profile = sGeckoThread.mProfile;
-        if (profile != null) {
-            return profile;
-        }
-        return sGeckoThread.getProfile();
+        return INSTANCE.getProfile();
     }
 
     public synchronized GeckoProfile getProfile() {
+        if (!mInitialized) {
+            return null;
+        }
+        if (isChildProcess()) {
+            throw new UnsupportedOperationException(
+                    "Cannot access profile from child process");
+        }
         if (mProfile == null) {
             final Context context = GeckoAppShell.getApplicationContext();
-            mProfile = GeckoProfile.initFromArgs(context, mArgs);
+            mProfile = GeckoProfile.initFromArgs(context, mExtraArgs);
         }
         return mProfile;
     }
 
     @Override
     public void run() {
         Log.i(LOGTAG, "preparing to run Gecko");
 
@@ -513,44 +538,50 @@ public class GeckoThread extends Thread 
                 idleMsg.obj = geckoHandler;
                 geckoHandler.sendMessageAtFrontOfQueue(idleMsg);
                 // Keep this IdleHandler
                 return true;
             }
         };
         Looper.myQueue().addIdleHandler(idleHandler);
 
-        if (mDebugging) {
-            try {
-                Thread.sleep(5 * 1000 /* 5 seconds */);
-            } catch (final InterruptedException e) {
-            }
-        }
-
-        final String[] args;
-        if (mChildProcessArgs != null) {
-            initGeckoEnvironment();
-            args = mChildProcessArgs;
-        } else {
-            args = getGeckoArgs(initGeckoEnvironment());
-        }
+        initGeckoEnvironment();
 
         // This can only happen after the call to initGeckoEnvironment
         // above, because otherwise the JNI code hasn't been loaded yet.
         ThreadUtils.postToUiThread(new Runnable() {
             @Override public void run() {
                 registerUiThread();
             }
         });
 
+        // Wait until initialization before calling Gecko entry point.
+        synchronized (this) {
+            while (!mInitialized) {
+                try {
+                    wait();
+                } catch (final InterruptedException e) {
+                }
+            }
+        }
+
+        final String[] args = isChildProcess() ? mArgs : getMainProcessArgs();
+
+        if (mDebugging) {
+            try {
+                Thread.sleep(5 * 1000 /* 5 seconds */);
+            } catch (final InterruptedException e) {
+            }
+        }
+
         Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - runGecko");
 
         final GeckoAppShell.GeckoInterface gi = GeckoAppShell.getGeckoInterface();
         if (gi == null || !gi.isOfficial()) {
-            Log.i(LOGTAG, "RunGecko - args = " + args);
+            Log.i(LOGTAG, "RunGecko - args = " + TextUtils.join(" ", args));
         }
 
         // And go.
         GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor);
 
         // And... we're done.
         setState(State.EXITED);
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java
@@ -509,25 +509,16 @@ public final class GeckoLoader {
         sMozGlueLoaded = true;
     }
 
     public synchronized static void loadGeckoLibs(final Context context, final String apkName) {
         loadLibsSetupLocked(context);
         loadGeckoLibsNative(apkName);
     }
 
-    public synchronized static void extractGeckoLibs(final Context context, final String apkName) {
-        loadLibsSetupLocked(context);
-        try {
-            extractGeckoLibsNative(apkName);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Failing library extraction.", e);
-        }
-    }
-
     private static void setupLocaleEnvironment() {
         putenv("LANG=" + Locale.getDefault().toString());
         NumberFormat nf = NumberFormat.getInstance();
         if (nf instanceof DecimalFormat) {
             DecimalFormat df = (DecimalFormat)nf;
             DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
 
             putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
@@ -556,10 +547,9 @@ public final class GeckoLoader {
     // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
     private static native void putenv(String map);
 
     // These methods are implemented in mozglue/android/APKOpen.cpp
     public static native void nativeRun(String[] args, int crashFd, int ipcFd);
     private static native void loadGeckoLibsNative(String apkName);
     private static native void loadSQLiteLibsNative(String apkName);
     private static native void loadNSSLibsNative(String apkName);
-    private static native void extractGeckoLibsNative(String apkName);
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java
@@ -69,17 +69,17 @@ public class GeckoServiceChildProcess ex
             serviceStarted = true;
             final int crashReporterFd = crashReporterPfd != null ? crashReporterPfd.detachFd() : -1;
             final int ipcFd = ipcPfd != null ? ipcPfd.detachFd() : -1;
             ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     GeckoAppShell.ensureCrashHandling();
                     GeckoAppShell.setApplicationContext(getApplicationContext());
-                    if (GeckoThread.initChildProcess(null, args, crashReporterFd, ipcFd, false)) {
+                    if (GeckoThread.initChildProcess(args, crashReporterFd, ipcFd)) {
                         GeckoThread.launch();
                     }
                 }
             });
         }
     };
 
     public IBinder onBind(final Intent intent) {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/FileUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/FileUtils.java
@@ -226,16 +226,20 @@ public class FileUtils {
         // by caching the returned matcher and calling `Matcher.reset` on it. Since Matcher's are not thread safe,
         // this assumes `FilenameFilter.accept` is not run in parallel (which, according to the source, it is not).
         private Matcher mCachedMatcher;
 
         public FilenameRegexFilter(final Pattern pattern) {
             mPattern = pattern;
         }
 
+        public FilenameRegexFilter(final String pattern) {
+            mPattern = Pattern.compile(pattern);
+        }
+
         @Override
         public boolean accept(final File dir, final String filename) {
             if (mCachedMatcher == null) {
                 mCachedMatcher = mPattern.matcher(filename);
             } else {
                 mCachedMatcher.reset(filename);
             }
             return mCachedMatcher.matches();
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/HardwareUtils.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.util;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.SysInfo;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.Build;
+import android.system.Os;
 import android.util.Log;
 
 import org.mozilla.gecko.SysInfo;
 import org.mozilla.geckoview.BuildConfig;
 
 public final class HardwareUtils {
     private static final String LOGTAG = "GeckoHardwareUtils";
 
@@ -80,32 +81,52 @@ public final class HardwareUtils {
         return SysInfo.getMemSize();
     }
 
     public static boolean isARMSystem() {
         return Build.CPU_ABI != null && Build.CPU_ABI.equals("armeabi-v7a");
     }
 
     public static boolean isX86System() {
-        return Build.CPU_ABI != null && Build.CPU_ABI.equals("x86");
+        if (Build.CPU_ABI != null && Build.CPU_ABI.equals("x86")) {
+            return true;
+        }
+        if (Build.VERSION.SDK_INT >= 21) {
+            // On some devices we have to look into the kernel release string.
+            try {
+                return Os.uname().release.contains("-x86_");
+            } catch (final Exception e) {
+                Log.w(LOGTAG, "Cannot get uname", e);
+            }
+        }
+        return false;
+    }
+
+    public static String getRealAbi() {
+        if (isX86System() && isARMSystem()) {
+            // Some x86 devices try to make us believe we're ARM,
+            // in which case CPU_ABI is not reliable.
+            return "x86";
+        }
+        return Build.CPU_ABI;
     }
 
     /**
      * @return false if the current system is not supported (e.g. APK/system ABI mismatch).
      */
     public static boolean isSupportedSystem() {
         // We've had crash reports from users on API 10 (with minSDK==15). That shouldn't even install,
         // but since it does we need to protect against it:
         if (Build.VERSION.SDK_INT < AppConstants.Versions.MIN_SDK_VERSION) {
             return false;
         }
 
         // See http://developer.android.com/ndk/guides/abis.html
-        final boolean isSystemARM = isARMSystem();
         final boolean isSystemX86 = isX86System();
+        final boolean isSystemARM = !isSystemX86 && isARMSystem();
 
         boolean isAppARM = BuildConfig.ANDROID_CPU_ARCH.startsWith("armeabi-v7a");
         boolean isAppX86 = BuildConfig.ANDROID_CPU_ARCH.startsWith("x86");
 
         // Only reject known incompatible ABIs. Better safe than sorry.
         if ((isSystemX86 && isAppARM) || (isSystemARM && isAppX86)) {
             return false;
         }
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -39,17 +39,17 @@ public class GeckoViewActivity extends A
     }
 
     @Override
     protected void onStart() {
         super.onStart();
 
         final GeckoProfile profile = GeckoProfile.get(getApplicationContext());
 
-        GeckoThread.init(profile, /* args */ null, /* action */ null, /* debugging */ false);
+        GeckoThread.initMainProcess(profile, /* args */ null, /* debugging */ false);
         GeckoThread.launch();
     }
 
     private class MyGeckoViewChrome implements GeckoView.ChromeDelegate {
         @Override
         public void onAlert(GeckoView view, String message, GeckoView.PromptResult result) {
             Log.i(LOGTAG, "Alert!");
             result.confirm();
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -320,41 +320,16 @@ loadNSSLibs(const char *apkName)
     return FAILURE;
   }
 #endif
 
   return setup_nss_functions(nss_handle, nspr_handle, plc_handle);
 }
 
 extern "C" APKOPEN_EXPORT void MOZ_JNICALL
-Java_org_mozilla_gecko_mozglue_GeckoLoader_extractGeckoLibsNative(
-    JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
-{
-  MOZ_ALWAYS_TRUE(!jenv->GetJavaVM(&sJavaVM));
-
-  const char* apkName = jenv->GetStringUTFChars(jApkName, nullptr);
-  if (apkName == nullptr) {
-    return;
-  }
-
-  // Extract and cache native lib to allow for efficient startup from cache.
-  void* handle = dlopenAPKLibrary(apkName, "libxul.so");
-  if (handle) {
-    __android_log_print(ANDROID_LOG_INFO, "GeckoLibLoad",
-                        "Extracted and cached libxul.so.");
-    // We have extracted and cached the lib, we can close it now.
-    __wrap_dlclose(handle);
-  } else {
-    JNI_Throw(jenv, "java/lang/Exception", "Error extracting gecko libraries");
-  }
-
-  jenv->ReleaseStringUTFChars(jApkName, apkName);
-}
-
-extern "C" APKOPEN_EXPORT void MOZ_JNICALL
 Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
 {
   jenv->GetJavaVM(&sJavaVM);
 
   const char* str;
   // XXX: java doesn't give us true UTF8, we should figure out something
   // better to do here
   str = jenv->GetStringUTFChars(jApkName, nullptr);
--- a/netwerk/base/nsAsyncRedirectVerifyHelper.cpp
+++ b/netwerk/base/nsAsyncRedirectVerifyHelper.cpp
@@ -24,18 +24,19 @@ static LazyLogModule gRedirectLog("nsRed
 NS_IMPL_ISUPPORTS(nsAsyncRedirectVerifyHelper,
                   nsIAsyncVerifyRedirectCallback,
                   nsIRunnable)
 
 class nsAsyncVerifyRedirectCallbackEvent : public Runnable {
 public:
     nsAsyncVerifyRedirectCallbackEvent(nsIAsyncVerifyRedirectCallback *cb,
                                        nsresult result)
-        : mCallback(cb), mResult(result) {
-    }
+        : Runnable("nsAsyncVerifyRedirectCallbackEvent")
+        , mCallback(cb)
+        , mResult(result) {}
 
     NS_IMETHOD Run() override
     {
         LOG(("nsAsyncVerifyRedirectCallbackEvent::Run() "
              "callback to %p with result %x",
              mCallback.get(), mResult));
        (void) mCallback->OnRedirectVerifyCallback(mResult);
        return NS_OK;
--- a/netwerk/protocol/http/nsHttpDigestAuth.cpp
+++ b/netwerk/protocol/http/nsHttpDigestAuth.cpp
@@ -561,18 +561,18 @@ nsHttpDigestAuth::ParseChallenge(const c
                                  uint16_t * algorithm,
                                  uint16_t * qop)
 {
   // put an absurd, but maximum, length cap on the challenge so
   // that calculations are 32 bit safe
   if (strlen(challenge) > 16000000) {
     return NS_ERROR_INVALID_ARG;
   }
-  
-  const char *p = challenge + 7; // first 7 characters are "Digest "
+
+  const char *p = challenge + 6; // first 6 characters are "Digest"
 
   *stale = false;
   *algorithm = ALGO_MD5; // default is MD5
   *qop = 0;
 
   for (;;) {
     while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
       ++p;
--- a/services/sync/modules/engines.js
+++ b/services/sync/modules/engines.js
@@ -599,17 +599,16 @@ EngineManager.prototype = {
         this._engines[name] = engine;
       }
     } catch (ex) {
       let name = engineObject || "";
       name = name.prototype || "";
       name = name.name || "";
 
       this._log.error(`Could not initialize engine ${name}`, ex);
-      return engineObject;
     }
   },
 
   unregister(val) {
     let name = val;
     if (val instanceof Engine) {
       name = val.name;
     }
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -584,18 +584,19 @@ StartupCache::ResetStartupWriteTimer()
   mStartupWriteInitiated = false;
   nsresult rv;
   if (!mTimer)
     mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
   else
     rv = mTimer->Cancel();
   NS_ENSURE_SUCCESS(rv, rv);
   // Wait for 10 seconds, then write out the cache.
-  mTimer->InitWithFuncCallback(StartupCache::WriteTimeout, this, 60000,
-                               nsITimer::TYPE_ONE_SHOT);
+  mTimer->InitWithNamedFuncCallback(StartupCache::WriteTimeout, this, 60000,
+                                    nsITimer::TYPE_ONE_SHOT,
+                                    "StartupCache::WriteTimeout");
   return NS_OK;
 }
 
 bool
 StartupCache::StartupWriteComplete()
 {
   WaitOnWriteThread();
   return mStartupWriteInitiated && mTable.Count() == 0;
--- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
+++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp
@@ -32,17 +32,18 @@ namespace {
  * Important note: we maintain the invariant that these private data
  * slots are already addrefed.
  */
 class FinalizationEvent final: public Runnable
 {
 public:
   FinalizationEvent(const char* aTopic,
                   const char16_t* aValue)
-    : mTopic(aTopic)
+    : Runnable("FinalizationEvent")
+    , mTopic(aTopic)
     , mValue(aValue)
   { }
 
   NS_IMETHOD Run() override {
     nsCOMPtr<nsIObserverService> observerService =
       mozilla::services::GetObserverService();
     if (!observerService) {
       // This is either too early or, more likely, too late for notifications.
--- a/toolkit/components/gfx/moz.build
+++ b/toolkit/components/gfx/moz.build
@@ -1,15 +1,12 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
-
-if toolkit == 'windows':
-    EXTRA_COMPONENTS += [
-        'GfxSanityTest.manifest',
-        'SanityTest.js',
-    ]
+EXTRA_COMPONENTS += [
+    'GfxSanityTest.manifest',
+    'SanityTest.js',
+]
 
 JAR_MANIFESTS += ['jar.mn']
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -25,17 +25,16 @@ DIRS += [
     'diskspacewatcher',
     'downloads',
     'extensions',
     'exthelper',
     'filewatcher',
     'finalizationwitness',
     'formautofill',
     'find',
-    'gfx',
     'jsdownloads',
     'lz4',
     'mediasniffer',
     'microformats',
     'mozprotocol',
     'osfile',
     'parentalcontrols',
     'passwordmgr',
@@ -46,17 +45,16 @@ DIRS += [
     'processsingleton',
     'promiseworker',
     'prompts',
     'protobuf',
     'reader',
     'remotebrowserutils',
     'reflect',
     'securityreporter',
-    'sqlite',
     'startup',
     'statusfilter',
     'telemetry',
     'thumbnails',
     'timermanager',
     'tooltiptext',
     'typeaheadfind',
     'utils',
@@ -98,13 +96,16 @@ if CONFIG['MOZ_TOOLKIT_SEARCH']:
 
 DIRS += ['captivedetect']
 
 if CONFIG['OS_TARGET'] != 'Android':
     DIRS += ['terminator']
 
 DIRS += ['build']
 
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
+    DIRS += ['gfx']
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     EXTRA_COMPONENTS += [
         'nsDefaultCLH.js',
         'nsDefaultCLH.manifest',
     ]
--- a/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
+++ b/toolkit/components/perfmonitoring/nsPerformanceStats.cpp
@@ -560,20 +560,24 @@ PerformanceAlert::GetReason(uint32_t* re
  * class PendingAlertsCollector
  *
  */
 
 /**
  * A timer callback in charge of collecting the groups in
  * `mPendingAlerts` and triggering dispatch of performance alerts.
  */
-class PendingAlertsCollector final: public nsITimerCallback {
+class PendingAlertsCollector final :
+  public nsITimerCallback,
+  public nsINamed
+{
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
+  NS_DECL_NSINAMED
 
   explicit PendingAlertsCollector(nsPerformanceStatsService* service)
     : mService(service)
     , mPending(false)
   { }
 
   nsresult Start(uint32_t timerDelayMS);
   nsresult Dispose();
@@ -584,25 +588,38 @@ private:
   RefPtr<nsPerformanceStatsService> mService;
   bool mPending;
 
   nsCOMPtr<nsITimer> mTimer;
 
   mozilla::Vector<uint64_t> mJankLevels;
 };
 
-NS_IMPL_ISUPPORTS(PendingAlertsCollector, nsITimerCallback);
+NS_IMPL_ISUPPORTS(PendingAlertsCollector, nsITimerCallback, nsINamed);
 
 NS_IMETHODIMP
 PendingAlertsCollector::Notify(nsITimer*) {
   mPending = false;
   mService->NotifyJankObservers(mJankLevels);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+PendingAlertsCollector::GetName(nsACString& aName)
+{
+  aName.AssignASCII("PendingAlertsCollector_timer");
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PendingAlertsCollector::SetName(const char* aName)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
 nsresult
 PendingAlertsCollector::Start(uint32_t timerDelayMS) {
   if (mPending) {
     // Collector is already started.
     return NS_OK;
   }
 
   if (!mTimer) {
deleted file mode 100644
--- a/toolkit/components/sqlite/moz.build
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
-
-EXTRA_JS_MODULES.sqlite += [
-    'sqlite_internal.js',
-]
deleted file mode 100644
--- a/toolkit/components/sqlite/sqlite_internal.js
+++ /dev/null
@@ -1,266 +0,0 @@
-/* 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/. */
-
-/* eslint-env commonjs, mozilla/chrome-worker */
-
-/**
- * This file defines an Sqlite object containing js-ctypes bindings for
- * sqlite3. It should be included from a worker thread using require.
- *
- * It serves the following purposes:
- * - opens libxul;
- * - defines sqlite3 API functions;
- * - defines the necessary sqlite3 types.
- */
-
-"use strict";
-
-importScripts("resource://gre/modules/workers/require.js");
-
-var SharedAll = require(
-  "resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
-
-// Open the sqlite3 library.
-var path;
-if (SharedAll.Constants.Sys.Name === "Android") {
-  path = ctypes.libraryName("sqlite3");
-} else if (SharedAll.Constants.Win) {
-  path = ctypes.libraryName("nss3");
-} else {
-  path = SharedAll.Constants.Path.libxul;
-}
-
-var lib;
-try {
-  lib = ctypes.open(path);
-} catch (ex) {
-  throw new Error("Could not open system library: " + ex.message);
-}
-
-var declareLazyFFI = SharedAll.declareLazyFFI;
-
-var Type = Object.create(SharedAll.Type);
-
-/**
- * Opaque Structure |sqlite3_ptr|.
- * |sqlite3_ptr| is equivalent to a void*.
- */
-Type.sqlite3_ptr = Type.voidptr_t.withName("sqlite3_ptr");
-
-/**
- * |sqlite3_stmt_ptr| an instance of an object representing a single SQL
- * statement.
- * |sqlite3_stmt_ptr| is equivalent to a void*.
- */
-Type.sqlite3_stmt_ptr = Type.voidptr_t.withName("sqlite3_stmt_ptr");
-
-/**
- * |sqlite3_destructor_ptr| a constant defining a special destructor behaviour.
- * |sqlite3_destructor_ptr| is equivalent to a void*.
- */
-Type.sqlite3_destructor_ptr = Type.voidptr_t.withName(
-  "sqlite3_destructor_ptr");
-
-/**
- * A C double.
- */
-Type.double = new SharedAll.Type("double", ctypes.double);
-
-/**
- * |sqlite3_int64| typedef for 64-bit integer.
- */
-Type.sqlite3_int64 = Type.int64_t.withName("sqlite3_int64");
-
-/**
- * Sqlite3 constants.
- */
-var Constants = {};
-
-/**
- * |SQLITE_STATIC| a special value for the destructor that is passed as an
- * argument to routines like bind_blob, bind_text and bind_text16. It means that
- * the content pointer is constant and will never change and does need to be
- * destroyed.
- */
-Constants.SQLITE_STATIC = Type.sqlite3_destructor_ptr.implementation(0);
-
-/**
- * |SQLITE_TRANSIENT| a special value for the destructor that is passed as an
- * argument to routines like bind_blob, bind_text and bind_text16. It means that
- * the content will likely change in the near future and that SQLite should make
- * its own private copy of the content before returning.
- */
-Constants.SQLITE_TRANSIENT = Type.sqlite3_destructor_ptr.implementation(-1);
-
-/**
- * |SQLITE_OK|
- * Successful result.
- */
-Constants.SQLITE_OK = 0;
-
-/**
- * |SQLITE_ROW|
- * sqlite3_step() has another row ready.
- */
-Constants.SQLITE_ROW = 100;
-
-/**
- * |SQLITE_DONE|
- * sqlite3_step() has finished executing.
- */
-Constants.SQLITE_DONE = 101;
-
-var Sqlite3 = {
-  Constants,
-  Type
-};
-
-declareLazyFFI(Sqlite3, "open", lib, "sqlite3_open", null, Type.int, Type.char.in_ptr,
-               /* db handle*/ Type.sqlite3_ptr.out_ptr);
-
-declareLazyFFI(Sqlite3, "open_v2", lib, "sqlite3_open_v2", null, Type.int, Type.char.in_ptr,
-               /* db handle*/ Type.sqlite3_ptr.out_ptr, Type.int, Type.char.in_ptr);
-
-declareLazyFFI(Sqlite3, "close", lib, "sqlite3_close", null, Type.int,
-               /* db handle*/ Type.sqlite3_ptr);
-
-declareLazyFFI(Sqlite3, "prepare_v2", lib, "sqlite3_prepare_v2", null, Type.int,
-               /* db handle*/ Type.sqlite3_ptr, Type.char.in_ptr, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr.out_ptr, Type.cstring.out_ptr);
-
-declareLazyFFI(Sqlite3, "step", lib, "sqlite3_step", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr);
-
-declareLazyFFI(Sqlite3, "finalize", lib, "sqlite3_finalize", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr);
-
-declareLazyFFI(Sqlite3, "reset", lib, "sqlite3_reset", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr);
-
-declareLazyFFI(Sqlite3, "column_int", lib, "sqlite3_column_int", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_blob", lib, "sqlite3_column_blob", null, Type.voidptr_t,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_bytes", lib, "sqlite3_column_bytes", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_bytes16", lib, "sqlite3_column_bytes16",
-                             null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_double", lib, "sqlite3_column_double", null, Type.double,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_int64", lib, "sqlite3_column_int64", null, Type.sqlite3_int64,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_text", lib, "sqlite3_column_text", null, Type.cstring,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "column_text16", lib, "sqlite3_column_text16", null, Type.wstring,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "bind_int", lib, "sqlite3_bind_int", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int, Type.int);
-
-declareLazyFFI(Sqlite3, "bind_int64", lib, "sqlite3_bind_int64", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int, Type.sqlite3_int64);
-
-declareLazyFFI(Sqlite3, "bind_double", lib, "sqlite3_bind_double", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int, Type.double);
-
-declareLazyFFI(Sqlite3, "bind_null", lib, "sqlite3_bind_null", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int);
-
-declareLazyFFI(Sqlite3, "bind_zeroblob", lib, "sqlite3_bind_zeroblob", null, Type.int,
-               /* statement*/ Type.sqlite3_stmt_ptr, Type.int, Type.int);
-
-declareLazyFFI(Sqlite3, "bind_text", lib, "sqlite3_bind_text", null, Type.int, Type.sqlite3_stmt_ptr, Type.int, Type.cstring, Type.int,
-               /* destructor*/ Type.sqlite3_destructor_ptr);
-
-declareLazyFFI(Sqlite3, "bind_text16", lib, "sqlite3_bind_text16", null, Type.int, Type.sqlite3_stmt_ptr, Type.int, Type.wstring, Type.int,
-               /* destructor*/ Type.sqlite3_destructor_ptr);
-
-declareLazyFFI(Sqlite3, "bind_blob", lib, "sqlite3_bind_blob", null, Type.int, Type.sqlite3_stmt_ptr, Type.int, Type.voidptr_t, Type.int,
-               /* destructor*/ Type.sqlite3_destructor_ptr);
-
-module.exports = {
-  get Constants() {
-    return Sqlite3.Constants;
-  },
-  get Type() {
-    return Sqlite3.Type;
-  },
-  get open() {
-    return Sqlite3.open;
-  },
-  get open_v2() {
-    return Sqlite3.open_v2;
-  },
-  get close() {
-    return Sqlite3.close;
-  },
-  get prepare_v2() {
-    return Sqlite3.prepare_v2;
-  },
-  get step() {
-    return Sqlite3.step;
-  },
-  get finalize() {
-    return Sqlite3.finalize;
-  },
-  get reset() {
-    return Sqlite3.reset;
-  },
-  get column_int() {
-    return Sqlite3.column_int;
-  },
-  get column_blob() {
-    return Sqlite3.column_blob;
-  },
-  get column_bytes() {
-    return Sqlite3.column_bytes;
-  },
-  get column_bytes16() {
-    return Sqlite3.column_bytes16;
-  },
-  get column_double() {
-    return Sqlite3.column_double;
-  },
-  get column_int64() {
-    return Sqlite3.column_int64;
-  },
-  get column_text() {
-    return Sqlite3.column_text;
-  },
-  get column_text16() {
-    return Sqlite3.column_text16;
-  },
-  get bind_int() {
-    return Sqlite3.bind_int;
-  },
-  get bind_int64() {
-    return Sqlite3.bind_int64;
-  },
-  get bind_double() {
-    return Sqlite3.bind_double;
-  },
-  get bind_null() {
-    return Sqlite3.bind_null;
-  },
-  get bind_zeroblob() {
-    return Sqlite3.bind_zeroblob;
-  },
-  get bind_text() {
-    return Sqlite3.bind_text;
-  },
-  get bind_text16() {
-    return Sqlite3.bind_text16;
-  },
-  get bind_blob() {
-    return Sqlite3.bind_blob;
-  }
-};
deleted file mode 100644
--- a/toolkit/components/sqlite/tests/xpcshell/.eslintrc.js
+++ /dev/null
@@ -1,7 +0,0 @@
-"use strict";
-
-module.exports = {
-  "extends": [
-    "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
-  ]
-};
deleted file mode 100644
--- a/toolkit/components/sqlite/tests/xpcshell/data/chrome.manifest
+++ /dev/null
@@ -1,1 +0,0 @@
-content test_sqlite_internal ./
deleted file mode 100644
--- a/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_internal.js
+++ /dev/null
@@ -1,281 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-/* eslint-env mozilla/chrome-worker */
-
-importScripts("worker_sqlite_shared.js",
-  "resource://gre/modules/workers/require.js");
-
-self.onmessage = function onmessage(msg) {
-  try {
-    run_test();
-  } catch (ex) {
-    let {message, moduleStack, moduleName, lineNumber} = ex;
-    let error = new Error(message, moduleName, lineNumber);
-    error.stack = moduleStack;
-    dump("Uncaught error: " + error + "\n");
-    dump("Full stack: " + moduleStack + "\n");
-    throw error;
-  }
-};
-
-var Sqlite;
-
-var SQLITE_OK;   /* Successful result */
-var SQLITE_ROW;  /* sqlite3_step() has another row ready */
-var SQLITE_DONE; /* sqlite3_step() has finished executing */
-
-function test_init() {
-  do_print("Starting test_init");
-  // Sqlite should be loaded.
-  Sqlite = require("resource://gre/modules/sqlite/sqlite_internal.js");
-  do_check_neq(typeof Sqlite, "undefined");
-  do_check_neq(typeof Sqlite.Constants, "undefined");
-  SQLITE_OK = Sqlite.Constants.SQLITE_OK;
-  SQLITE_ROW = Sqlite.Constants.SQLITE_ROW;
-  SQLITE_DONE = Sqlite.Constants.SQLITE_DONE;
-}
-
-/**
- * Clean up the database.
- * @param  {sqlite3_ptr} db A pointer to the database.
- */
-function cleanupDB(db) {
-  withQuery(db, "DROP TABLE IF EXISTS TEST;", SQLITE_DONE);
-}
-
-/**
- * Open and close sqlite3 database.
- * @param  {String}   open            A name of the sqlite3 open function to be
- *                                    used.
- * @param  {Array}    openArgs = []   Optional arguments to open function.
- * @param  {Function} callback = null An optional callback to be run after the
- *                                    database is opened but before it is
- *                                    closed.
- */
-function withDB(open, openArgs = [], callback = null) {
-  let db = Sqlite.Type.sqlite3_ptr.implementation();
-  let dbPtr = db.address();
-
-  // Open database.
-  let result = Sqlite[open].apply(Sqlite, ["data/test.db", dbPtr].concat(
-    openArgs));
-  do_check_eq(result, SQLITE_OK);
-
-  // Drop the test table if it already exists.
-  cleanupDB(db);
-
-  try {
-    if (callback) {
-      callback(db);
-    }
-  } catch (ex) {
-    do_check_true(false);
-    throw ex;
-  } finally {
-    // Drop the test table if it still exists.
-    cleanupDB(db);
-    // Close data base.
-    result = Sqlite.close(db);
-    do_check_eq(result, SQLITE_OK);
-  }
-}
-
-/**
- * Execute an SQL query using sqlite3 API.
- * @param  {sqlite3_ptr} db         A pointer to the database.
- * @param  {String}      sql        A SQL query string.
- * @param  {Number}      stepResult Expected result code after evaluating the
- *                                  SQL statement.
- * @param  {Function}    bind       An optional callback with SQL binding steps.
- * @param  {Function}    callback   An optional callback that runs after the SQL
- *                                  query completes.
- */
-function withQuery(db, sql, stepResult, bind, callback) {
-  // Create an instance of a single SQL statement.
-  let sqlStmt = Sqlite.Type.sqlite3_stmt_ptr.implementation();
-  let sqlStmtPtr = sqlStmt.address();
-
-  // Unused portion of an SQL query.
-  let unused = Sqlite.Type.cstring.implementation();
-  let unusedPtr = unused.address();
-
-  // Compile an SQL statement.
-  let result = Sqlite.prepare_v2(db, sql, sql.length, sqlStmtPtr, unusedPtr);
-  do_check_eq(result, SQLITE_OK);
-
-  try {
-    if (bind) {
-      bind(sqlStmt);
-    }
-
-    // Evaluate an SQL statement.
-    result = Sqlite.step(sqlStmt);
-    do_check_eq(result, stepResult);
-
-    if (callback) {
-      callback(sqlStmt);
-    }
-  } catch (ex) {
-    do_check_true(false);
-    throw ex;
-  } finally {
-    // Destroy a prepared statement object.
-    result = Sqlite.finalize(sqlStmt);
-    do_check_eq(result, SQLITE_OK);
-  }
-}
-
-function test_open_close() {
-  do_print("Starting test_open_close");
-  do_check_eq(typeof Sqlite.open, "function");
-  do_check_eq(typeof Sqlite.close, "function");
-
-  withDB("open");
-}
-
-function test_open_v2_close() {
-  do_print("Starting test_open_v2_close");
-  do_check_eq(typeof Sqlite.open_v2, "function");
-
-  withDB("open_v2", [0x02, null]);
-}
-
-function createTableOnOpen(db) {
-  withQuery(db, "CREATE TABLE TEST(" +
-              "ID INT PRIMARY KEY NOT NULL," +
-              "FIELD1 INT," +
-              "FIELD2 REAL," +
-              "FIELD3 TEXT," +
-              "FIELD4 TEXT," +
-              "FIELD5 BLOB" +
-            ");", SQLITE_DONE);
-}
-
-function test_create_table() {
-  do_print("Starting test_create_table");
-  do_check_eq(typeof Sqlite.prepare_v2, "function");
-  do_check_eq(typeof Sqlite.step, "function");
-  do_check_eq(typeof Sqlite.finalize, "function");
-
-  withDB("open", [], createTableOnOpen);
-}
-
-/**
- * Read column values after evaluating the SQL SELECT statement.
- * @param  {sqlite3_stmt_ptr} sqlStmt A pointer to the SQL statement.
- */
-function onSqlite3Step(sqlStmt) {
-  // Get an int value from a query result from the ID (column 0).
-  let field = Sqlite.column_int(sqlStmt, 0);
-  do_check_eq(field, 3);
-
-  // Get an int value from a query result from the column 1.
-  field = Sqlite.column_int(sqlStmt, 1);
-  do_check_eq(field, 2);
-  // Get an int64 value from a query result from the column 1.
-  field = Sqlite.column_int64(sqlStmt, 1);
-  do_check_eq(field, 2);
-
-  // Get a double value from a query result from the column 2.
-  field = Sqlite.column_double(sqlStmt, 2);
-  do_check_eq(field, 1.2);
-
-  // Get a number of bytes of the value in the column 3.
-  let bytes = Sqlite.column_bytes(sqlStmt, 3);
-  do_check_eq(bytes, 4);
-  // Get a text(cstring) value from a query result from the column 3.
-  field = Sqlite.column_text(sqlStmt, 3);
-  do_check_eq(field.readString(), "DATA");
-
-  // Get a number of bytes of the UTF-16 value in the column 4.
-  bytes = Sqlite.column_bytes16(sqlStmt, 4);
-  do_check_eq(bytes, 8);
-  // Get a text16(wstring) value from a query result from the column 4.
-  field = Sqlite.column_text16(sqlStmt, 4);
-  do_check_eq(field.readString(), "TADA");
-
-  // Get a blob value from a query result from the column 5.
-  field = Sqlite.column_blob(sqlStmt, 5);
-  do_check_eq(ctypes.cast(field,
-    Sqlite.Type.cstring.implementation).readString(), "BLOB");
-}
-
-function test_insert_select() {
-  do_print("Starting test_insert_select");
-  do_check_eq(typeof Sqlite.column_int, "function");
-  do_check_eq(typeof Sqlite.column_int64, "function");
-  do_check_eq(typeof Sqlite.column_double, "function");
-  do_check_eq(typeof Sqlite.column_bytes, "function");
-  do_check_eq(typeof Sqlite.column_text, "function");
-  do_check_eq(typeof Sqlite.column_text16, "function");
-  do_check_eq(typeof Sqlite.column_blob, "function");
-
-  function onOpen(db) {
-    createTableOnOpen(db);
-    withQuery(db,
-      "INSERT INTO TEST VALUES (3, 2, 1.2, \"DATA\", \"TADA\", \"BLOB\");",
-      SQLITE_DONE);
-    withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step);
-  }
-
-  withDB("open", [], onOpen);
-}
-
-function test_insert_bind_select() {
-  do_print("Starting test_insert_bind_select");
-  do_check_eq(typeof Sqlite.bind_int, "function");
-  do_check_eq(typeof Sqlite.bind_int64, "function");
-  do_check_eq(typeof Sqlite.bind_double, "function");
-  do_check_eq(typeof Sqlite.bind_text, "function");
-  do_check_eq(typeof Sqlite.bind_text16, "function");
-  do_check_eq(typeof Sqlite.bind_blob, "function");
-
-  function onBind(sqlStmt) {
-    // Bind an int value to the ID (column 0).
-    let result = Sqlite.bind_int(sqlStmt, 1, 3);
-    do_check_eq(result, SQLITE_OK);
-
-    // Bind an int64 value to the FIELD1 (column 1).
-    result = Sqlite.bind_int64(sqlStmt, 2, 2);
-    do_check_eq(result, SQLITE_OK);
-
-    // Bind a double value to the FIELD2 (column 2).
-    result = Sqlite.bind_double(sqlStmt, 3, 1.2);
-    do_check_eq(result, SQLITE_OK);
-
-    // Destructor.
-    let destructor = Sqlite.Constants.SQLITE_TRANSIENT;
-    // Bind a text value to the FIELD3 (column 3).
-    result = Sqlite.bind_text(sqlStmt, 4, "DATA", 4, destructor);
-    do_check_eq(result, SQLITE_OK);
-
-    // Bind a text16 value to the FIELD4 (column 4).
-    result = Sqlite.bind_text16(sqlStmt, 5, "TADA", 8, destructor);
-    do_check_eq(result, SQLITE_OK);
-
-    // Bind a blob value to the FIELD5 (column 5).
-    result = Sqlite.bind_blob(sqlStmt, 6, ctypes.char.array()("BLOB"), 4,
-      destructor);
-    do_check_eq(result, SQLITE_OK);
-  }
-
-  function onOpen(db) {
-    createTableOnOpen(db);
-    withQuery(db, "INSERT INTO TEST VALUES (?, ?, ?, ?, ?, ?);", SQLITE_DONE,
-      onBind);
-    withQuery(db, "SELECT * FROM TEST;", SQLITE_ROW, null, onSqlite3Step);
-  }
-
-  withDB("open", [], onOpen);
-}
-
-function run_test() {
-  test_init();
-  test_open_close();
-  test_open_v2_close();
-  test_create_table();
-  test_insert_select();
-  test_insert_bind_select();
-  do_test_complete();
-}
deleted file mode 100644
--- a/toolkit/components/sqlite/tests/xpcshell/data/worker_sqlite_shared.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativec