Merge inbound to m-c on a CLOSED TREE. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 26 Jun 2014 17:13:04 -0400
changeset 191059 3519e987aa3bba37b00dfe70e1382b4a5832d374
parent 190990 398a5f3142c150f26a2b41a53f5b8b22b4966e78 (current diff)
parent 191058 d874785394e120b94f029bbe94f842acea334193 (diff)
child 191060 6c1da87675d9adbc5e666fee97be4281f5e8d012
child 191067 3bef42144aabe8efccce8edbe40f82bc1bf39385
child 191103 40139a7bd1b172f7d2891a75a8c1f6398abf5472
child 191152 759429576b4baa003eb6080526d9987af53a8c47
push id27024
push userryanvm@gmail.com
push dateThu, 26 Jun 2014 21:13:08 +0000
treeherdermozilla-central@3519e987aa3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.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 inbound to m-c on a CLOSED TREE. a=merge
editor/composer/public/moz.build
editor/composer/public/nsIEditingSession.idl
editor/composer/src/crashtests/351236-1.html
editor/composer/src/crashtests/407062-1.html
editor/composer/src/crashtests/419563-1.xhtml
editor/composer/src/crashtests/428844-1-inner.xhtml
editor/composer/src/crashtests/428844-1.html
editor/composer/src/crashtests/461049-1.html
editor/composer/src/crashtests/crashtests.list
editor/composer/src/crashtests/removing-editable-xslt-inner.xhtml
editor/composer/src/crashtests/removing-editable-xslt.html
editor/composer/src/moz.build
editor/composer/src/nsComposeTxtSrvFilter.cpp
editor/composer/src/nsComposeTxtSrvFilter.h
editor/composer/src/nsComposerCommands.cpp
editor/composer/src/nsComposerCommands.h
editor/composer/src/nsComposerCommandsUpdater.cpp
editor/composer/src/nsComposerCommandsUpdater.h
editor/composer/src/nsComposerController.cpp
editor/composer/src/nsComposerController.h
editor/composer/src/nsComposerDocumentCommands.cpp
editor/composer/src/nsComposerRegistration.cpp
editor/composer/src/nsEditingSession.cpp
editor/composer/src/nsEditingSession.h
editor/composer/src/nsEditorSpellCheck.cpp
editor/composer/src/nsEditorSpellCheck.h
editor/composer/src/res/EditorOverride.css
editor/composer/src/res/grabber.gif
editor/composer/src/res/table-add-column-after-active.gif
editor/composer/src/res/table-add-column-after-hover.gif
editor/composer/src/res/table-add-column-after.gif
editor/composer/src/res/table-add-column-before-active.gif
editor/composer/src/res/table-add-column-before-hover.gif
editor/composer/src/res/table-add-column-before.gif
editor/composer/src/res/table-add-row-after-active.gif
editor/composer/src/res/table-add-row-after-hover.gif
editor/composer/src/res/table-add-row-after.gif
editor/composer/src/res/table-add-row-before-active.gif
editor/composer/src/res/table-add-row-before-hover.gif
editor/composer/src/res/table-add-row-before.gif
editor/composer/src/res/table-remove-column-active.gif
editor/composer/src/res/table-remove-column-hover.gif
editor/composer/src/res/table-remove-column.gif
editor/composer/src/res/table-remove-row-active.gif
editor/composer/src/res/table-remove-row-hover.gif
editor/composer/src/res/table-remove-row.gif
editor/composer/src/res/text_caret.png
editor/composer/src/res/text_caret@1.5x.png
editor/composer/src/res/text_caret@2.25x.png
editor/composer/src/res/text_caret@2x.png
editor/composer/src/res/text_caret_tilt_left.png
editor/composer/src/res/text_caret_tilt_left@1.5x.png
editor/composer/src/res/text_caret_tilt_left@2.25x.png
editor/composer/src/res/text_caret_tilt_left@2x.png
editor/composer/src/res/text_caret_tilt_right.png
editor/composer/src/res/text_caret_tilt_right@1.5x.png
editor/composer/src/res/text_caret_tilt_right@2.25x.png
editor/composer/src/res/text_caret_tilt_right@2x.png
editor/composer/src/res/text_selection_handle.png
editor/composer/src/res/text_selection_handle@1.5.png
editor/composer/src/res/text_selection_handle@2.png
editor/txmgr/idl/moz.build
editor/txmgr/idl/nsITransaction.idl
editor/txmgr/idl/nsITransactionList.idl
editor/txmgr/idl/nsITransactionListener.idl
editor/txmgr/idl/nsITransactionManager.idl
editor/txmgr/public/moz.build
editor/txmgr/public/nsTransactionManagerCID.h
editor/txmgr/src/moz.build
editor/txmgr/src/nsTransactionItem.cpp
editor/txmgr/src/nsTransactionItem.h
editor/txmgr/src/nsTransactionList.cpp
editor/txmgr/src/nsTransactionList.h
editor/txmgr/src/nsTransactionManager.cpp
editor/txmgr/src/nsTransactionManager.h
editor/txmgr/src/nsTransactionManagerFactory.cpp
editor/txmgr/src/nsTransactionStack.cpp
editor/txmgr/src/nsTransactionStack.h
editor/txtsvc/public/moz.build
editor/txtsvc/public/nsIInlineSpellChecker.idl
editor/txtsvc/public/nsISpellChecker.h
editor/txtsvc/public/nsITextService.h
editor/txtsvc/public/nsITextServicesDocument.h
editor/txtsvc/public/nsITextServicesFilter.idl
editor/txtsvc/public/nsTextServicesCID.h
editor/txtsvc/src/moz.build
editor/txtsvc/src/nsFilteredContentIterator.cpp
editor/txtsvc/src/nsFilteredContentIterator.h
editor/txtsvc/src/nsTSAtomList.h
editor/txtsvc/src/nsTextServicesDocument.cpp
editor/txtsvc/src/nsTextServicesDocument.h
editor/txtsvc/src/nsTextServicesFactory.cpp
tools/profiler/BreakpadSampler.cpp
tools/profiler/GeckoProfilerFunc.h
tools/profiler/TableTicker.cpp
tools/profiler/TableTicker.h
tools/profiler/ThreadResponsiveness.cpp
tools/profiler/platform.cpp
xpcom/string/public/moz.build
xpcom/string/public/nsAString.h
xpcom/string/public/nsAlgorithm.h
xpcom/string/public/nsCharTraits.h
xpcom/string/public/nsDependentString.h
xpcom/string/public/nsDependentSubstring.h
xpcom/string/public/nsEmbedString.h
xpcom/string/public/nsLiteralString.h
xpcom/string/public/nsPrintfCString.h
xpcom/string/public/nsPromiseFlatString.h
xpcom/string/public/nsReadableUtils.h
xpcom/string/public/nsString.h
xpcom/string/public/nsStringBuffer.h
xpcom/string/public/nsStringFwd.h
xpcom/string/public/nsStringIterator.h
xpcom/string/public/nsSubstring.h
xpcom/string/public/nsSubstringTuple.h
xpcom/string/public/nsTDependentString.h
xpcom/string/public/nsTDependentSubstring.h
xpcom/string/public/nsTLiteralString.h
xpcom/string/public/nsTPromiseFlatString.h
xpcom/string/public/nsTString.h
xpcom/string/public/nsTSubstring.h
xpcom/string/public/nsTSubstringTuple.h
xpcom/string/public/nsUTF8Utils.h
xpcom/string/public/nsXPCOMStrings.h
xpcom/string/public/nsXPIDLString.h
xpcom/string/public/string-template-def-char.h
xpcom/string/public/string-template-def-unichar.h
xpcom/string/public/string-template-undef.h
xpcom/string/src/moz.build
xpcom/string/src/nsDependentString.cpp
xpcom/string/src/nsDependentSubstring.cpp
xpcom/string/src/nsPromiseFlatString.cpp
xpcom/string/src/nsReadableUtils.cpp
xpcom/string/src/nsString.cpp
xpcom/string/src/nsStringComparator.cpp
xpcom/string/src/nsStringObsolete.cpp
xpcom/string/src/nsSubstring.cpp
xpcom/string/src/nsSubstringTuple.cpp
xpcom/string/src/nsTDependentString.cpp
xpcom/string/src/nsTDependentSubstring.cpp
xpcom/string/src/nsTPromiseFlatString.cpp
xpcom/string/src/nsTString.cpp
xpcom/string/src/nsTStringComparator.cpp
xpcom/string/src/nsTStringObsolete.cpp
xpcom/string/src/nsTSubstring.cpp
xpcom/string/src/nsTSubstringTuple.cpp
xpcom/string/src/nsUTF8UtilsSSE2.cpp
--- a/Makefile.in
+++ b/Makefile.in
@@ -290,13 +290,13 @@ source-package install:
 .PHONY: config/export
 config/export:
 
 endif
 
 ifdef MOZ_PSEUDO_DERECURSE
 # Interdependencies for parallel export.
 js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
-accessible/src/xpcom/export: xpcom/xpidl/export
+accessible/xpcom/export: xpcom/xpidl/export
 ifdef ENABLE_CLANG_PLUGIN
 js/src/export config/export: build/clang-plugin/export
 endif
 endif
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -116,26 +116,16 @@ class EventTarget;
 class NodeInfo;
 class Selection;
 } // namespace dom
 
 namespace layers {
 class LayerManager;
 } // namespace layers
 
-// Called back from DeferredFinalize.  Should add 'thing' to the array of smart
-// pointers in 'pointers', creating the array if 'pointers' is null, and return
-// the array.
-typedef void* (*DeferredFinalizeAppendFunction)(void* pointers, void* thing);
-
-// Called to finalize a number of objects. Slice is the number of objects
-// to finalize, or if it's UINT32_MAX, all objects should be finalized.
-// Return value indicates whether it finalized all objects in the buffer.
-typedef bool (*DeferredFinalizeFunction)(uint32_t slice, void* data);
-
 } // namespace mozilla
 
 class nsIBidiKeyboard;
 
 extern const char kLoadAsData[];
 
 // Stolen from nsReadableUtils, but that's OK, since we can declare the same
 // name multiple times.
@@ -1275,21 +1265,16 @@ public:
   static void DestroyMatchString(void* aData);
 
   /**
    * Unbinds the content from the tree and nulls it out if it's not null.
    */
   static void DestroyAnonymousContent(nsCOMPtr<nsIContent>* aContent);
   static void DestroyAnonymousContent(nsCOMPtr<Element>* aElement);
 
-  static void DeferredFinalize(nsISupports* aSupports);
-  static void DeferredFinalize(mozilla::DeferredFinalizeAppendFunction aAppendFunc,
-                               mozilla::DeferredFinalizeFunction aFunc,
-                               void* aThing);
-
   /*
    * Notify when the first XUL menu is opened and when the all XUL menus are
    * closed. At opening, aInstalling should be TRUE, otherwise, it should be
    * FALSE.
    */
   static void NotifyInstalledMenuKeyboardListener(bool aInstalling);
 
   /**
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -34,117 +34,409 @@
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
-class nsDOMFileBase : public nsIDOMFile,
-                      public nsIXHRSendable,
-                      public nsIMutable
+namespace mozilla {
+namespace dom {
+
+namespace indexedDB {
+class FileInfo;
+};
+
+class DOMFileImpl;
+
+// XXX bug 827823 will get rid of DOMFileBase
+class DOMFileBase : public nsIDOMFile
+                  , public nsIXHRSendable
+                  , public nsIMutable
+                  , public nsIJSNativeInitializer
 {
-  friend class nsDOMMultipartFile;
+  // XXX bug 827823 will get rid of DOMFileCC
+  friend class DOMFileCC;
 
 public:
-  typedef mozilla::dom::indexedDB::FileInfo FileInfo;
+  NS_DECL_NSIDOMBLOB
+  NS_DECL_NSIDOMFILE
+  NS_DECL_NSIXHRSENDABLE
+  NS_DECL_NSIMUTABLE
+
+  DOMFileBase(DOMFileImpl* aImpl)
+    : mImpl(aImpl)
+  {
+    MOZ_ASSERT(mImpl);
+  }
+
+  DOMFileImpl* Impl() const
+  {
+    return mImpl;
+  }
+
+  const nsTArray<nsCOMPtr<nsIDOMBlob>>* GetSubBlobs() const;
+
+  bool IsSizeUnknown() const;
+
+  bool IsDateUnknown() const;
+
+  bool IsFile() const;
+
+  void SetLazyData(const nsAString& aName, const nsAString& aContentType,
+                   uint64_t aLength, uint64_t aLastModifiedDate);
+
+  already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType);
+
+  // nsIJSNativeInitializer
+  NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
+                        const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+
+protected:
+  virtual ~DOMFileBase() {};
+
+private:
+  // The member is the real backend implementation of this DOMFile/DOMBlob.
+  // It's thread-safe and not CC-able and it's the only element that is moved
+  // between threads.
+  const nsRefPtr<DOMFileImpl> mImpl;
+};
+
+// XXX bug 827823 - this class should be MOZ_FINAL
+class DOMFile : public DOMFileBase
+{
+public:
+  // XXX bug 827823 will make this class CC and not thread-safe
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  static already_AddRefed<DOMFile>
+  Create(const nsAString& aName, const nsAString& aContentType,
+         uint64_t aLength, uint64_t aLastModifiedDate);
+
+  static already_AddRefed<DOMFile>
+  Create(const nsAString& aName, const nsAString& aContentType,
+         uint64_t aLength);
+
+  static already_AddRefed<DOMFile>
+  Create(const nsAString& aContentType, uint64_t aLength);
+
+  static already_AddRefed<DOMFile>
+  Create(const nsAString& aContentType, uint64_t aStart,
+         uint64_t aLength);
+
+  static already_AddRefed<DOMFile>
+  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+                   const nsAString& aName, const nsAString& aContentType,
+                   uint64_t aLastModifiedDate);
+
+  static already_AddRefed<DOMFile>
+  CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+                   const nsAString& aContentType);
+
+  static already_AddRefed<DOMFile>
+  CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                          uint64_t aLength,
+                          const nsAString& aContentType);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(nsIFile* aFile);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(const nsAString& aContentType, uint64_t aLength,
+                 nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(const nsAString& aName, const nsAString& aContentType,
+                 uint64_t aLength, nsIFile* aFile,
+                    indexedDB::FileInfo* aFileInfo);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo);
+
+  static already_AddRefed<DOMFile>
+  CreateFromFile(nsIFile* aFile, const nsAString& aName,
+                 const nsAString& aContentType);
+
+  explicit DOMFile(DOMFileImpl* aImpl)
+    : DOMFileBase(aImpl)
+  {}
+
+protected:
+  virtual ~DOMFile() {};
+};
+
+// XXX bug 827823 will get rid of this class
+class DOMFileCC MOZ_FINAL : public DOMFileBase
+{
+public:
+  DOMFileCC(DOMFileImpl* aImpl)
+    : DOMFileBase(aImpl)
+  {}
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMFileCC, nsIDOMFile)
+
+protected:
+  virtual ~DOMFileCC() {};
+};
+
+// This is the virtual class for any DOMFile backend. It must be nsISupports
+// because this class must be ref-counted and it has to work with IPC.
+class DOMFileImpl : public nsISupports
+{
+public:
+  DOMFileImpl()
+  {
+  }
+
+  virtual nsresult GetName(nsAString& aName) = 0;
+
+  virtual nsresult GetPath(nsAString& aName) = 0;
+
+  virtual nsresult
+  GetLastModifiedDate(JSContext* aCx,
+                      JS::MutableHandle<JS::Value> aDate) = 0;
+
+  virtual nsresult GetMozFullPath(nsAString& aName) = 0;
+
+  virtual nsresult GetMozFullPathInternal(nsAString &aFileName) = 0;
+
+  virtual nsresult GetSize(uint64_t* aSize) = 0;
+
+  virtual nsresult GetType(nsAString& aType) = 0;
+
+  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) = 0;
+
+  nsresult Slice(int64_t aStart, int64_t aEnd, const nsAString& aContentType,
+                 uint8_t aArgc, nsIDOMBlob **aBlob);
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType) = 0;
 
-  virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
-  GetSubBlobs() const { return nullptr; }
+  virtual const nsTArray<nsCOMPtr<nsIDOMBlob>>*
+  GetSubBlobs() const = 0;
+
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) = 0;
+
+  virtual nsresult
+  GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL) = 0;
+
+  virtual int64_t GetFileId() = 0;
+
+  virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) = 0;
+
+  virtual indexedDB::FileInfo*
+  GetFileInfo(indexedDB::FileManager* aFileManager) = 0;
+
+  virtual nsresult GetSendInfo(nsIInputStream** aBody,
+                               uint64_t* aContentLength,
+                               nsACString& aContentType,
+                               nsACString& aCharset) = 0;
+
+  virtual nsresult GetMutable(bool* aMutable) const = 0;
+
+  virtual nsresult SetMutable(bool aMutable) = 0;
+
+  virtual void SetLazyData(const nsAString& aName,
+                           const nsAString& aContentType,
+                           uint64_t aLength,
+                           uint64_t aLastModifiedDate) = 0;
+
+  virtual bool IsMemoryFile() const = 0;
+
+  virtual bool IsSizeUnknown() const = 0;
+
+  virtual bool IsDateUnknown() const = 0;
+
+  virtual bool IsFile() const = 0;
+
+  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
+                              JSObject* aObj, const JS::CallArgs& aArgs) = 0;
+
+  // These 2 methods are used when the implementation has to CC something.
+  virtual void Unlink() = 0;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) = 0;
+
+protected:
+  virtual ~DOMFileImpl() {}
+};
+
+class DOMFileImplBase : public DOMFileImpl
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+  DOMFileImplBase(const nsAString& aName, const nsAString& aContentType,
+                  uint64_t aLength, uint64_t aLastModifiedDate)
+    : mIsFile(true)
+    , mImmutable(false)
+    , mContentType(aContentType)
+    , mName(aName)
+    , mStart(0)
+    , mLength(aLength)
+    , mLastModificationDate(aLastModifiedDate)
+  {
+    // Ensure non-null mContentType by default
+    mContentType.SetIsVoid(false);
+  }
 
-  NS_DECL_NSIDOMBLOB
-  NS_DECL_NSIDOMFILE
-  NS_DECL_NSIXHRSENDABLE
-  NS_DECL_NSIMUTABLE
+  DOMFileImplBase(const nsAString& aName, const nsAString& aContentType,
+                  uint64_t aLength)
+    : mIsFile(true)
+    , mImmutable(false)
+    , mContentType(aContentType)
+    , mName(aName)
+    , mStart(0)
+    , mLength(aLength)
+    , mLastModificationDate(UINT64_MAX)
+  {
+    // Ensure non-null mContentType by default
+    mContentType.SetIsVoid(false);
+  }
+
+  DOMFileImplBase(const nsAString& aContentType, uint64_t aLength)
+    : mIsFile(false)
+    , mImmutable(false)
+    , mContentType(aContentType)
+    , mStart(0)
+    , mLength(aLength)
+    , mLastModificationDate(UINT64_MAX)
+  {
+    // Ensure non-null mContentType by default
+    mContentType.SetIsVoid(false);
+  }
+
+  DOMFileImplBase(const nsAString& aContentType, uint64_t aStart,
+                  uint64_t aLength)
+    : mIsFile(false)
+    , mImmutable(false)
+    , mContentType(aContentType)
+    , mStart(aStart)
+    , mLength(aLength)
+    , mLastModificationDate(UINT64_MAX)
+  {
+    NS_ASSERTION(aLength != UINT64_MAX,
+                 "Must know length when creating slice");
+    // Ensure non-null mContentType by default
+    mContentType.SetIsVoid(false);
+  }
+
+  virtual nsresult GetName(nsAString& aName) MOZ_OVERRIDE;
+
+  virtual nsresult GetPath(nsAString& aName) MOZ_OVERRIDE;
 
-  void
+  virtual nsresult GetLastModifiedDate(JSContext* aCx,
+                               JS::MutableHandle<JS::Value> aDate) MOZ_OVERRIDE;
+
+  virtual nsresult GetMozFullPath(nsAString& aName) MOZ_OVERRIDE;
+
+  virtual nsresult GetMozFullPathInternal(nsAString& aFileName) MOZ_OVERRIDE;
+
+  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+
+  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
+
+  virtual nsresult GetMozLastModifiedDate(uint64_t* aDate) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType) MOZ_OVERRIDE;
+
+  virtual const nsTArray<nsCOMPtr<nsIDOMBlob>>*
+  GetSubBlobs() const MOZ_OVERRIDE
+  {
+    return nullptr;
+  }
+
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+
+  virtual nsresult GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL) MOZ_OVERRIDE;
+
+  virtual int64_t GetFileId() MOZ_OVERRIDE;
+
+  virtual void AddFileInfo(indexedDB::FileInfo* aFileInfo) MOZ_OVERRIDE;
+
+  virtual indexedDB::FileInfo*
+  GetFileInfo(indexedDB::FileManager* aFileManager) MOZ_OVERRIDE;
+
+  virtual nsresult GetSendInfo(nsIInputStream** aBody,
+                               uint64_t* aContentLength,
+                               nsACString& aContentType,
+                               nsACString& aCharset) MOZ_OVERRIDE;
+
+  virtual nsresult GetMutable(bool* aMutable) const MOZ_OVERRIDE;
+
+  virtual nsresult SetMutable(bool aMutable) MOZ_OVERRIDE;
+
+  virtual void
   SetLazyData(const nsAString& aName, const nsAString& aContentType,
-              uint64_t aLength, uint64_t aLastModifiedDate)
+              uint64_t aLength, uint64_t aLastModifiedDate) MOZ_OVERRIDE
   {
     NS_ASSERTION(aLength, "must have length");
 
     mName = aName;
     mContentType = aContentType;
     mLength = aLength;
     mLastModificationDate = aLastModifiedDate;
     mIsFile = !aName.IsVoid();
   }
 
-  bool IsSizeUnknown() const
+  virtual bool IsMemoryFile() const MOZ_OVERRIDE
   {
-    return mLength == UINT64_MAX;
+    return false;
   }
 
-  bool IsDateUnknown() const
+  virtual bool IsDateUnknown() const MOZ_OVERRIDE
   {
     return mIsFile && mLastModificationDate == UINT64_MAX;
   }
 
-protected:
-  nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, uint64_t aLastModifiedDate)
-    : mIsFile(true), mImmutable(false), mContentType(aContentType),
-      mName(aName), mStart(0), mLength(aLength), mLastModificationDate(aLastModifiedDate)
+  virtual bool IsFile() const
   {
-    // Ensure non-null mContentType by default
-    mContentType.SetIsVoid(false);
-  }
-
-  nsDOMFileBase(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength)
-    : mIsFile(true), mImmutable(false), mContentType(aContentType),
-      mName(aName), mStart(0), mLength(aLength), mLastModificationDate(UINT64_MAX)
-  {
-    // Ensure non-null mContentType by default
-    mContentType.SetIsVoid(false);
+    return mIsFile;
   }
 
-  nsDOMFileBase(const nsAString& aContentType, uint64_t aLength)
-    : mIsFile(false), mImmutable(false), mContentType(aContentType),
-      mStart(0), mLength(aLength), mLastModificationDate(UINT64_MAX)
-  {
-    // Ensure non-null mContentType by default
-    mContentType.SetIsVoid(false);
-  }
-
-  nsDOMFileBase(const nsAString& aContentType, uint64_t aStart,
-                uint64_t aLength)
-    : mIsFile(false), mImmutable(false), mContentType(aContentType),
-      mStart(aStart), mLength(aLength), mLastModificationDate(UINT64_MAX)
-  {
-    NS_ASSERTION(aLength != UINT64_MAX,
-                 "Must know length when creating slice");
-    // Ensure non-null mContentType by default
-    mContentType.SetIsVoid(false);
-  }
-
-  virtual ~nsDOMFileBase() {}
-
   virtual bool IsStoredFile() const
   {
     return false;
   }
 
   virtual bool IsWholeFile() const
   {
     NS_NOTREACHED("Should only be called on dom blobs backed by files!");
     return false;
   }
 
   virtual bool IsSnapshot() const
   {
     return false;
   }
 
-  FileInfo* GetFileInfo() const
+  virtual bool IsSizeUnknown() const
+  {
+    return mLength == UINT64_MAX;
+  }
+
+  virtual nsresult Initialize(nsISupports* aOwner, JSContext* aCx,
+                              JSObject* aObj, const JS::CallArgs& aArgs)
+  {
+    return NS_OK;
+  }
+
+  virtual void Unlink() {}
+  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) {}
+
+protected:
+  virtual ~DOMFileImplBase() {}
+
+  indexedDB::FileInfo* GetFileInfo() const
   {
     NS_ASSERTION(IsStoredFile(), "Should only be called on stored files!");
     NS_ASSERTION(!mFileInfos.IsEmpty(), "Must have at least one file info!");
 
     return mFileInfos.ElementAt(0);
   }
 
   bool mIsFile;
@@ -155,269 +447,55 @@ protected:
   nsString mPath; // The path relative to a directory chosen by the user
 
   uint64_t mStart;
   uint64_t mLength;
 
   uint64_t mLastModificationDate;
 
   // Protected by IndexedDatabaseManager::FileMutex()
-  nsTArray<nsRefPtr<FileInfo> > mFileInfos;
-};
-
-class nsDOMFile : public nsDOMFileBase
-{
-public:
-  nsDOMFile(const nsAString& aName, const nsAString& aContentType,
-            uint64_t aLength, uint64_t aLastModifiedDate)
-  : nsDOMFileBase(aName, aContentType, aLength, aLastModifiedDate)
-  { }
-
-  nsDOMFile(const nsAString& aName, const nsAString& aContentType,
-            uint64_t aLength)
-  : nsDOMFileBase(aName, aContentType, aLength)
-  { }
-
-  nsDOMFile(const nsAString& aContentType, uint64_t aLength)
-  : nsDOMFileBase(aContentType, aLength)
-  { }
-
-  nsDOMFile(const nsAString& aContentType, uint64_t aStart, uint64_t aLength)
-  : nsDOMFileBase(aContentType, aStart, aLength)
-  { }
-
-  NS_DECL_THREADSAFE_ISUPPORTS
-
-protected:
-  ~nsDOMFile() {}
-};
-
-class nsDOMFileCC : public nsDOMFileBase
-{
-public:
-  nsDOMFileCC(const nsAString& aName, const nsAString& aContentType,
-              uint64_t aLength)
-  : nsDOMFileBase(aName, aContentType, aLength)
-  { }
-
-  nsDOMFileCC(const nsAString& aContentType, uint64_t aLength)
-  : nsDOMFileBase(aContentType, aLength)
-  { }
-
-  nsDOMFileCC(const nsAString& aContentType, uint64_t aStart, uint64_t aLength)
-  : nsDOMFileBase(aContentType, aStart, aLength)
-  { }
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMFileCC, nsIDOMFile)
-
-protected:
-  ~nsDOMFileCC() {}
-};
-
-class nsDOMFileFile : public nsDOMFile
-{
-public:
-  // Create as a file
-  nsDOMFileFile(nsIFile *aFile)
-    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX),
-      mFile(aFile), mWholeFile(true), mStoredFile(false)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    // Lazily get the content type and size
-    mContentType.SetIsVoid(true);
-    mFile->GetLeafName(mName);
-  }
-
-  nsDOMFileFile(nsIFile *aFile, FileInfo *aFileInfo)
-    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX),
-      mFile(aFile), mWholeFile(true), mStoredFile(true)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    NS_ASSERTION(aFileInfo, "must have file info");
-    // Lazily get the content type and size
-    mContentType.SetIsVoid(true);
-    mFile->GetLeafName(mName);
-
-    mFileInfos.AppendElement(aFileInfo);
-  }
-
-  // Create as a file
-  nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, nsIFile *aFile)
-    : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
-      mFile(aFile), mWholeFile(true), mStoredFile(false)
-  {
-    NS_ASSERTION(mFile, "must have file");
-  }
-
-  nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, nsIFile *aFile, uint64_t aLastModificationDate)
-    : nsDOMFile(aName, aContentType, aLength, aLastModificationDate),
-      mFile(aFile), mWholeFile(true), mStoredFile(false)
-  {
-    NS_ASSERTION(mFile, "must have file");
-  }
-
-  // Create as a file with custom name
-  nsDOMFileFile(nsIFile *aFile, const nsAString& aName,
-                const nsAString& aContentType)
-    : nsDOMFile(aName, aContentType, UINT64_MAX, UINT64_MAX),
-      mFile(aFile), mWholeFile(true), mStoredFile(false)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    if (aContentType.IsEmpty()) {
-      // Lazily get the content type and size
-      mContentType.SetIsVoid(true);
-    }
-  }
-
-  // Create as a stored file
-  nsDOMFileFile(const nsAString& aName, const nsAString& aContentType,
-                uint64_t aLength, nsIFile* aFile,
-                FileInfo* aFileInfo)
-    : nsDOMFile(aName, aContentType, aLength, UINT64_MAX),
-      mFile(aFile), mWholeFile(true), mStoredFile(true)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    mFileInfos.AppendElement(aFileInfo);
-  }
-
-  // Create as a stored blob
-  nsDOMFileFile(const nsAString& aContentType, uint64_t aLength,
-                nsIFile* aFile, FileInfo* aFileInfo)
-    : nsDOMFile(aContentType, aLength),
-      mFile(aFile), mWholeFile(true), mStoredFile(true)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    mFileInfos.AppendElement(aFileInfo);
-  }
-
-  // Create as a file to be later initialized
-  nsDOMFileFile()
-    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX),
-      mWholeFile(true), mStoredFile(false)
-  {
-    // Lazily get the content type and size
-    mContentType.SetIsVoid(true);
-    mName.SetIsVoid(true);
-  }
-
-  // Overrides
-  NS_IMETHOD GetSize(uint64_t* aSize) MOZ_OVERRIDE;
-  NS_IMETHOD GetType(nsAString& aType) MOZ_OVERRIDE;
-  NS_IMETHOD GetLastModifiedDate(JSContext* cx, JS::MutableHandle<JS::Value> aLastModifiedDate) MOZ_OVERRIDE;
-  NS_IMETHOD GetMozLastModifiedDate(uint64_t* aLastModifiedDate) MOZ_OVERRIDE;
-  NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
-  NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
-
-  void SetPath(const nsAString& aFullPath);
-
-protected:
-  ~nsDOMFileFile() {}
-
-  // Create slice
-  nsDOMFileFile(const nsDOMFileFile* aOther, uint64_t aStart, uint64_t aLength,
-                const nsAString& aContentType)
-    : nsDOMFile(aContentType, aOther->mStart + aStart, aLength),
-      mFile(aOther->mFile), mWholeFile(false),
-      mStoredFile(aOther->mStoredFile)
-  {
-    NS_ASSERTION(mFile, "must have file");
-    mImmutable = aOther->mImmutable;
-
-    if (mStoredFile) {
-      FileInfo* fileInfo;
-
-      using mozilla::dom::indexedDB::IndexedDatabaseManager;
-
-      if (IndexedDatabaseManager::IsClosed()) {
-        fileInfo = aOther->GetFileInfo();
-      }
-      else {
-        mozilla::MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
-        fileInfo = aOther->GetFileInfo();
-      }
-
-      mFileInfos.AppendElement(fileInfo);
-    }
-  }
-
-  virtual already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
-
-  virtual bool IsStoredFile() const MOZ_OVERRIDE
-  {
-    return mStoredFile;
-  }
-
-  virtual bool IsWholeFile() const MOZ_OVERRIDE
-  {
-    return mWholeFile;
-  }
-
-  nsCOMPtr<nsIFile> mFile;
-  bool mWholeFile;
-  bool mStoredFile;
+  nsTArray<nsRefPtr<indexedDB::FileInfo>> mFileInfos;
 };
 
 /**
  * This class may be used off the main thread, and in particular, its
  * constructor and destructor may not run on the same thread.  Be careful!
  */
-class nsDOMMemoryFile : public nsDOMFile
+class DOMFileImplMemory MOZ_FINAL : public DOMFileImplBase
 {
 public:
-  // Create as file
-  nsDOMMemoryFile(void *aMemoryBuffer,
-                  uint64_t aLength,
-                  const nsAString& aName,
-                  const nsAString& aContentType,
-                  uint64_t aLastModifiedDate)
-    : nsDOMFile(aName, aContentType, aLength, aLastModifiedDate),
-      mDataOwner(new DataOwner(aMemoryBuffer, aLength))
+  DOMFileImplMemory(void* aMemoryBuffer, uint64_t aLength,
+                    const nsAString& aName,
+                    const nsAString& aContentType,
+                    uint64_t aLastModifiedDate)
+    : DOMFileImplBase(aName, aContentType, aLength, aLastModifiedDate)
+    , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
-  // Create as blob
-  nsDOMMemoryFile(void *aMemoryBuffer,
-                  uint64_t aLength,
-                  const nsAString& aContentType)
-    : nsDOMFile(aContentType, aLength),
-      mDataOwner(new DataOwner(aMemoryBuffer, aLength))
+  DOMFileImplMemory(void* aMemoryBuffer,
+                    uint64_t aLength,
+                    const nsAString& aContentType)
+    : DOMFileImplBase(aContentType, aLength)
+    , mDataOwner(new DataOwner(aMemoryBuffer, aLength))
   {
     NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
   }
 
-  NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
-
-  NS_IMETHOD_(bool) IsMemoryFile(void) MOZ_OVERRIDE;
-
-protected:
-  ~nsDOMMemoryFile() {}
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  // Create slice
-  nsDOMMemoryFile(const nsDOMMemoryFile* aOther, uint64_t aStart,
-                  uint64_t aLength, const nsAString& aContentType)
-    : nsDOMFile(aContentType, aOther->mStart + aStart, aLength),
-      mDataOwner(aOther->mDataOwner)
-  {
-    NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
-    mImmutable = aOther->mImmutable;
-  }
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType) MOZ_OVERRIDE;
 
-  // These classes need to see DataOwner.
-  friend class DataOwnerAdapter;
-  friend class nsDOMMemoryFileDataOwnerMemoryReporter;
+  virtual bool IsMemoryFile() const MOZ_OVERRIDE
+  {
+    return true;
+  }
 
   class DataOwner MOZ_FINAL : public mozilla::LinkedListElement<DataOwner> {
   public:
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DataOwner)
     DataOwner(void* aMemoryBuffer, uint64_t aLength)
       : mData(aMemoryBuffer)
       , mLength(aLength)
     {
@@ -453,20 +531,248 @@ protected:
     static mozilla::StaticMutex sDataOwnerMutex;
     static mozilla::StaticAutoPtr<mozilla::LinkedList<DataOwner> > sDataOwners;
     static bool sMemoryReporterRegistered;
 
     void* mData;
     uint64_t mLength;
   };
 
+private:
+  // Create slice
+  DOMFileImplMemory(const DOMFileImplMemory* aOther, uint64_t aStart,
+                    uint64_t aLength, const nsAString& aContentType)
+    : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength)
+    , mDataOwner(aOther->mDataOwner)
+  {
+    NS_ASSERTION(mDataOwner && mDataOwner->mData, "must have data");
+    mImmutable = aOther->mImmutable;
+  }
+
+  ~DOMFileImplMemory() {}
+
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
+class DOMFileImplTemporaryFileBlob MOZ_FINAL : public DOMFileImplBase
+{
+public:
+  DOMFileImplTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                               uint64_t aLength, const nsAString& aContentType)
+    : DOMFileImplBase(aContentType, aLength)
+    , mLength(aLength)
+    , mStartPos(aStartPos)
+    , mContentType(aContentType)
+  {
+    mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
+  }
+
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType) MOZ_OVERRIDE;
+
+private:
+  DOMFileImplTemporaryFileBlob(const DOMFileImplTemporaryFileBlob* aOther,
+                               uint64_t aStart, uint64_t aLength,
+                               const nsAString& aContentType)
+    : DOMFileImplBase(aContentType, aLength)
+    , mLength(aLength)
+    , mStartPos(aStart)
+    , mFileDescOwner(aOther->mFileDescOwner)
+    , mContentType(aContentType) {}
+
+  ~DOMFileImplTemporaryFileBlob() {}
+
+  uint64_t mLength;
+  uint64_t mStartPos;
+  nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
+  nsString mContentType;
+};
+
+class DOMFileImplFile MOZ_FINAL : public DOMFileImplBase
+{
+public:
+  // Create as a file
+  explicit DOMFileImplFile(nsIFile* aFile)
+    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(false)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    // Lazily get the content type and size
+    mContentType.SetIsVoid(true);
+    mFile->GetLeafName(mName);
+  }
+
+  DOMFileImplFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(true)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    NS_ASSERTION(aFileInfo, "must have file info");
+    // Lazily get the content type and size
+    mContentType.SetIsVoid(true);
+    mFile->GetLeafName(mName);
+
+    mFileInfos.AppendElement(aFileInfo);
+  }
+
+  // Create as a file
+  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
+                  uint64_t aLength, nsIFile* aFile)
+    : DOMFileImplBase(aName, aContentType, aLength, UINT64_MAX)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(false)
+  {
+    NS_ASSERTION(mFile, "must have file");
+  }
+
+  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
+                  uint64_t aLength, nsIFile* aFile,
+                  uint64_t aLastModificationDate)
+    : DOMFileImplBase(aName, aContentType, aLength, aLastModificationDate)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(false)
+  {
+    NS_ASSERTION(mFile, "must have file");
+  }
+
+  // Create as a file with custom name
+  DOMFileImplFile(nsIFile* aFile, const nsAString& aName,
+                  const nsAString& aContentType)
+    : DOMFileImplBase(aName, aContentType, UINT64_MAX, UINT64_MAX)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(false)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    if (aContentType.IsEmpty()) {
+      // Lazily get the content type and size
+      mContentType.SetIsVoid(true);
+    }
+  }
+
+  // Create as a stored file
+  DOMFileImplFile(const nsAString& aName, const nsAString& aContentType,
+                  uint64_t aLength, nsIFile* aFile,
+                  indexedDB::FileInfo* aFileInfo)
+    : DOMFileImplBase(aName, aContentType, aLength, UINT64_MAX)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(true)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    mFileInfos.AppendElement(aFileInfo);
+  }
+
+  // Create as a stored blob
+  DOMFileImplFile(const nsAString& aContentType, uint64_t aLength,
+                  nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+    : DOMFileImplBase(aContentType, aLength)
+    , mFile(aFile)
+    , mWholeFile(true)
+    , mStoredFile(true)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    mFileInfos.AppendElement(aFileInfo);
+  }
+
+  // Create as a file to be later initialized
+  DOMFileImplFile()
+    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    , mWholeFile(true)
+    , mStoredFile(false)
+  {
+    // Lazily get the content type and size
+    mContentType.SetIsVoid(true);
+    mName.SetIsVoid(true);
+  }
+
+  // Overrides
+  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
+  virtual nsresult GetType(nsAString& aType) MOZ_OVERRIDE;
+  virtual nsresult GetLastModifiedDate(JSContext* aCx,
+                               JS::MutableHandle<JS::Value> aLastModifiedDate) MOZ_OVERRIDE;
+  virtual nsresult GetMozLastModifiedDate(uint64_t* aLastModifiedDate) MOZ_OVERRIDE;
+  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
+
+  void SetPath(const nsAString& aFullPath);
+
+private:
+  // Create slice
+  DOMFileImplFile(const DOMFileImplFile* aOther, uint64_t aStart,
+                  uint64_t aLength, const nsAString& aContentType)
+    : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength)
+    , mFile(aOther->mFile)
+    , mWholeFile(false)
+    , mStoredFile(aOther->mStoredFile)
+  {
+    NS_ASSERTION(mFile, "must have file");
+    mImmutable = aOther->mImmutable;
+
+    if (mStoredFile) {
+      indexedDB::FileInfo* fileInfo;
+
+      using indexedDB::IndexedDatabaseManager;
+
+      if (IndexedDatabaseManager::IsClosed()) {
+        fileInfo = aOther->GetFileInfo();
+      }
+      else {
+        mozilla::MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
+        fileInfo = aOther->GetFileInfo();
+      }
+
+      mFileInfos.AppendElement(fileInfo);
+    }
+  }
+
+  ~DOMFileImplFile() {}
+
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType) MOZ_OVERRIDE;
+
+  virtual bool IsStoredFile() const MOZ_OVERRIDE
+  {
+    return mStoredFile;
+  }
+
+  virtual bool IsWholeFile() const MOZ_OVERRIDE
+  {
+    return mWholeFile;
+  }
+
+  nsCOMPtr<nsIFile> mFile;
+  bool mWholeFile;
+  bool mStoredFile;
+};
+
+} // dom namespace
+} // file namespace
+
+class MOZ_STACK_CLASS nsDOMFileInternalUrlHolder {
+public:
+  nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile, nsIPrincipal* aPrincipal
+                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+  ~nsDOMFileInternalUrlHolder();
+  nsAutoString mUrl;
+private:
+  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
 class nsDOMFileList MOZ_FINAL : public nsIDOMFileList,
                                 public nsWrapperCache
 {
   ~nsDOMFileList() {}
 
 public:
   nsDOMFileList(nsISupports *aParent) : mParent(aParent)
   {
@@ -526,55 +832,9 @@ public:
     return mFiles.Count();
   }
 
 private:
   nsCOMArray<nsIDOMFile> mFiles;
   nsISupports *mParent;
 };
 
-class MOZ_STACK_CLASS nsDOMFileInternalUrlHolder {
-public:
-  nsDOMFileInternalUrlHolder(nsIDOMBlob* aFile, nsIPrincipal* aPrincipal
-                             MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-  ~nsDOMFileInternalUrlHolder();
-  nsAutoString mUrl;
-private:
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-// This class would take the ownership of aFD and the caller must not close it.
-class nsDOMTemporaryFileBlob : public nsDOMFile
-{
-public:
-  nsDOMTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos, uint64_t aLength,
-                         const nsAString& aContentType)
-    : nsDOMFile(aContentType, aLength),
-      mLength(aLength),
-      mStartPos(aStartPos),
-      mContentType(aContentType)
-  {
-    mFileDescOwner = new nsTemporaryFileInputStream::FileDescOwner(aFD);
-  }
-
-  ~nsDOMTemporaryFileBlob() { }
-  NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
-
-protected:
-  nsDOMTemporaryFileBlob(const nsDOMTemporaryFileBlob* aOther, uint64_t aStart, uint64_t aLength,
-                         const nsAString& aContentType)
-    : nsDOMFile(aContentType, aLength),
-      mLength(aLength),
-      mStartPos(aStart),
-      mFileDescOwner(aOther->mFileDescOwner),
-      mContentType(aContentType) { }
-
-  virtual already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength,
-              const nsAString& aContentType) MOZ_OVERRIDE;
-
-private:
-  uint64_t mLength;
-  uint64_t mStartPos;
-  nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
-  nsString mContentType;
-};
-
 #endif
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -5968,17 +5968,18 @@ nsContentUtils::CreateBlobBuffer(JSConte
                                  const nsACString& aData,
                                  JS::MutableHandle<JS::Value> aBlob)
 {
   uint32_t blobLen = aData.Length();
   void* blobData = moz_malloc(blobLen);
   nsCOMPtr<nsIDOMBlob> blob;
   if (blobData) {
     memcpy(blobData, aData.BeginReading(), blobLen);
-    blob = new nsDOMMemoryFile(blobData, blobLen, EmptyString());
+    blob = mozilla::dom::DOMFile::CreateMemoryFile(blobData, blobLen,
+                                                   EmptyString());
   } else {
     return NS_ERROR_OUT_OF_MEMORY;
   }
   return nsContentUtils::WrapNative(aCx, blob, aBlob);
 }
 
 void
 nsContentUtils::StripNullChars(const nsAString& aInStr, nsAString& aOutStr)
@@ -6061,32 +6062,16 @@ nsContentUtils::AllocClassMatchingInfo(n
 
   info->mCaseTreatment =
     aRootNode->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks ?
     eIgnoreCase : eCaseMatters;
   return info;
 }
 
 // static
-void
-nsContentUtils::DeferredFinalize(nsISupports* aSupports)
-{
-  cyclecollector::DeferredFinalize(aSupports);
-}
-
-// static
-void
-nsContentUtils::DeferredFinalize(mozilla::DeferredFinalizeAppendFunction aAppendFunc,
-                                 mozilla::DeferredFinalizeFunction aFunc,
-                                 void* aThing)
-{
-  cyclecollector::DeferredFinalize(aAppendFunc, aFunc, aThing);
-}
-
-// static
 bool
 nsContentUtils::IsFocusedContent(const nsIContent* aContent)
 {
   nsFocusManager* fm = nsFocusManager::GetFocusManager();
 
   return fm && fm->GetFocusedContent() == aContent;
 }
 
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -16,28 +16,25 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIXPConnect.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
-NS_IMPL_ISUPPORTS_INHERITED(nsDOMMultipartFile, nsDOMFile,
-                            nsIJSNativeInitializer)
-
-NS_IMETHODIMP
-nsDOMMultipartFile::GetSize(uint64_t* aLength)
+nsresult
+DOMMultipartFileImpl::GetSize(uint64_t* aLength)
 {
   *aLength = mLength;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMMultipartFile::GetInternalStream(nsIInputStream** aStream)
+nsresult
+DOMMultipartFileImpl::GetInternalStream(nsIInputStream** aStream)
 {
   nsresult rv;
   *aStream = nullptr;
 
   nsCOMPtr<nsIMultiplexInputStream> stream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
@@ -52,18 +49,18 @@ nsDOMMultipartFile::GetInternalStream(ns
     rv = stream->AppendStream(scratchStream);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return CallQueryInterface(stream, aStream);
 }
 
 already_AddRefed<nsIDOMBlob>
-nsDOMMultipartFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                const nsAString& aContentType)
+DOMMultipartFileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+                                  const nsAString& aContentType)
 {
   // If we clamped to nothing we create an empty blob
   nsTArray<nsCOMPtr<nsIDOMBlob> > blobs;
 
   uint64_t length = aLength;
   uint64_t skipStart = aStart;
 
   // Prune the list of blobs if we can
@@ -79,17 +76,17 @@ nsDOMMultipartFile::CreateSlice(uint64_t
       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
 
       nsCOMPtr<nsIDOMBlob> firstBlob;
       rv = blob->Slice(skipStart, skipStart + upperBound,
                        aContentType, 3,
                        getter_AddRefs(firstBlob));
       NS_ENSURE_SUCCESS(rv, nullptr);
 
-      // Avoid wrapping a single blob inside an nsDOMMultipartFile
+      // Avoid wrapping a single blob inside an DOMMultipartFileImpl
       if (length == upperBound) {
         return firstBlob.forget();
       }
 
       blobs.AppendElement(firstBlob);
       length -= upperBound;
       i++;
       break;
@@ -114,49 +111,51 @@ nsDOMMultipartFile::CreateSlice(uint64_t
       blobs.AppendElement(lastBlob);
     } else {
       blobs.AppendElement(blob);
     }
     length -= std::min<uint64_t>(l, length);
   }
 
   // we can create our blob now
-  nsCOMPtr<nsIDOMBlob> blob = new nsDOMMultipartFile(blobs, aContentType);
+  nsCOMPtr<nsIDOMBlob> blob =
+    new DOMFile(new DOMMultipartFileImpl(blobs, aContentType));
   return blob.forget();
 }
 
 /* static */ nsresult
-nsDOMMultipartFile::NewFile(const nsAString& aName, nsISupports* *aNewObject)
+DOMMultipartFileImpl::NewFile(const nsAString& aName, nsISupports** aNewObject)
 {
   nsCOMPtr<nsISupports> file =
-    do_QueryObject(new nsDOMMultipartFile(aName));
+    do_QueryObject(new DOMFile(new DOMMultipartFileImpl(aName)));
   file.forget(aNewObject);
   return NS_OK;
 }
 
 /* static */ nsresult
-nsDOMMultipartFile::NewBlob(nsISupports* *aNewObject)
+DOMMultipartFileImpl::NewBlob(nsISupports** aNewObject)
 {
-  nsCOMPtr<nsISupports> file = do_QueryObject(new nsDOMMultipartFile());
+  nsCOMPtr<nsISupports> file =
+    do_QueryObject(new DOMFile(new DOMMultipartFileImpl()));
   file.forget(aNewObject);
   return NS_OK;
 }
 
 static nsIDOMBlob*
 GetXPConnectNative(JSContext* aCx, JSObject* aObj) {
   nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(
     nsContentUtils::XPConnect()->GetNativeOfWrapper(aCx, aObj));
   return blob;
 }
 
-NS_IMETHODIMP
-nsDOMMultipartFile::Initialize(nsISupports* aOwner,
-                               JSContext* aCx,
-                               JSObject* aObj,
-                               const JS::CallArgs& aArgs)
+nsresult
+DOMMultipartFileImpl::Initialize(nsISupports* aOwner,
+                                 JSContext* aCx,
+                                 JSObject* aObj,
+                                 const JS::CallArgs& aArgs)
 {
   if (!mIsFile) {
     return InitBlob(aCx, aArgs.length(), aArgs.array(), GetXPConnectNative);
   }
 
   if (!nsContentUtils::IsCallerChrome()) {
     return InitFile(aCx, aArgs.length(), aArgs.array());
   }
@@ -170,20 +169,20 @@ nsDOMMultipartFile::Initialize(nsISuppor
       }
     }
   }
 
   return InitChromeFile(aCx, aArgs.length(), aArgs.array());
 }
 
 nsresult
-nsDOMMultipartFile::InitBlob(JSContext* aCx,
-                             uint32_t aArgc,
-                             JS::Value* aArgv,
-                             UnwrapFuncPtr aUnwrapFunc)
+DOMMultipartFileImpl::InitBlob(JSContext* aCx,
+                               uint32_t aArgc,
+                               JS::Value* aArgv,
+                               UnwrapFuncPtr aUnwrapFunc)
 {
   bool nativeEOL = false;
   if (aArgc > 1) {
     BlobPropertyBag d;
     if (!d.Init(aCx, JS::Handle<JS::Value>::fromMarkedLocation(&aArgv[1]))) {
       return NS_ERROR_TYPE_ERR;
     }
     mContentType = d.mType;
@@ -195,19 +194,19 @@ nsDOMMultipartFile::InitBlob(JSContext* 
   }
 
   SetLengthAndModifiedDate();
 
   return NS_OK;
 }
 
 nsresult
-nsDOMMultipartFile::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
-                                           bool aNativeEOL,
-                                           UnwrapFuncPtr aUnwrapFunc)
+DOMMultipartFileImpl::ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
+                                             bool aNativeEOL,
+                                             UnwrapFuncPtr aUnwrapFunc)
 {
   if (!aValue.isObject()) {
     return NS_ERROR_TYPE_ERR; // We're not interested
   }
 
   JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
   if (!JS_IsArrayObject(aCx, obj)) {
     return NS_ERROR_TYPE_ERR; // We're not interested
@@ -222,20 +221,18 @@ nsDOMMultipartFile::ParseBlobArrayArgume
     if (!JS_GetElement(aCx, obj, i, &element))
       return NS_ERROR_TYPE_ERR;
 
     if (element.isObject()) {
       JS::Rooted<JSObject*> obj(aCx, &element.toObject());
       nsCOMPtr<nsIDOMBlob> blob = aUnwrapFunc(aCx, obj);
       if (blob) {
         // Flatten so that multipart blobs will never nest
-        nsDOMFileBase* file = static_cast<nsDOMFileBase*>(
-            static_cast<nsIDOMBlob*>(blob));
-        const nsTArray<nsCOMPtr<nsIDOMBlob> >*
-            subBlobs = file->GetSubBlobs();
+        DOMFile* file = static_cast<DOMFile*>(static_cast<nsIDOMBlob*>(blob));
+        const nsTArray<nsCOMPtr<nsIDOMBlob>>* subBlobs = file->GetSubBlobs();
         if (subBlobs) {
           blobSet.AppendBlobs(*subBlobs);
         } else {
           blobSet.AppendBlob(blob);
         }
         continue;
       }
       if (JS_IsArrayBufferViewObject(obj)) {
@@ -263,31 +260,31 @@ nsDOMMultipartFile::ParseBlobArrayArgume
   mBlobs = blobSet.GetBlobs();
 
   SetLengthAndModifiedDate();
 
   return NS_OK;
 }
 
 void
-nsDOMMultipartFile::SetLengthAndModifiedDate()
+DOMMultipartFileImpl::SetLengthAndModifiedDate()
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == UINT64_MAX);
 
   uint64_t totalLength = 0;
 
   for (uint32_t index = 0, count = mBlobs.Length(); index < count; index++) {
     nsCOMPtr<nsIDOMBlob>& blob = mBlobs[index];
 
 #ifdef DEBUG
     {
       // XXX This is only safe so long as all blob implementations in our tree
       //     inherit nsDOMFileBase.
-      const auto* blobBase = static_cast<nsDOMFileBase*>(blob.get());
+      const auto* blobBase = static_cast<DOMFile*>(blob.get());
 
       MOZ_ASSERT(!blobBase->IsSizeUnknown());
       MOZ_ASSERT(!blobBase->IsDateUnknown());
     }
 #endif
 
     uint64_t subBlobLength;
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
@@ -298,36 +295,36 @@ nsDOMMultipartFile::SetLengthAndModified
 
   mLength = totalLength;
 
   if (mIsFile) {
     mLastModificationDate = PR_Now();
   }
 }
 
-NS_IMETHODIMP
-nsDOMMultipartFile::GetMozFullPathInternal(nsAString &aFilename)
+nsresult
+DOMMultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename)
 {
   if (!mIsFromNsiFile || mBlobs.Length() == 0) {
-    return nsDOMFile::GetMozFullPathInternal(aFilename);
+    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
   }
 
   nsIDOMBlob* blob = mBlobs.ElementAt(0).get();
-  nsDOMFileFile* file = static_cast<nsDOMFileFile*>(blob);
-  if (!file) {
-    return nsDOMFile::GetMozFullPathInternal(aFilename);
+  if (!blob) {
+    return DOMFileImplBase::GetMozFullPathInternal(aFilename);
   }
 
-  return file->GetMozFullPathInternal(aFilename);
+  DOMFile* domFile = static_cast<DOMFile*>(blob);
+  return domFile->GetMozFullPathInternal(aFilename);
 }
 
 nsresult
-nsDOMMultipartFile::InitChromeFile(JSContext* aCx,
-                                   uint32_t aArgc,
-                                   JS::Value* aArgv)
+DOMMultipartFileImpl::InitChromeFile(JSContext* aCx,
+                                     uint32_t aArgc,
+                                     JS::Value* aArgv)
 {
   nsresult rv;
 
   NS_ASSERTION(!mImmutable, "Something went wrong ...");
   NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
   MOZ_ASSERT(nsContentUtils::IsCallerChrome());
   NS_ENSURE_TRUE(aArgc > 0, NS_ERROR_UNEXPECTED);
 
@@ -390,17 +387,17 @@ nsDOMMultipartFile::InitChromeFile(JSCon
     rv = file->IsDirectory(&isDir);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_FALSE(isDir, NS_ERROR_FILE_IS_DIRECTORY);
 
     if (mName.IsEmpty()) {
       file->GetLeafName(mName);
     }
 
-    nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
+    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
 
     // Pre-cache size.
     uint64_t unused;
     rv = domFile->GetSize(&unused);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Pre-cache modified date.
     rv = domFile->GetMozLastModifiedDate(&unused);
@@ -419,19 +416,19 @@ nsDOMMultipartFile::InitChromeFile(JSCon
   mBlobs = blobSet.GetBlobs();
 
   SetLengthAndModifiedDate();
 
   return NS_OK;
 }
 
 nsresult
-nsDOMMultipartFile::InitFile(JSContext* aCx,
-                             uint32_t aArgc,
-                             JS::Value* aArgv)
+DOMMultipartFileImpl::InitFile(JSContext* aCx,
+                               uint32_t aArgc,
+                               JS::Value* aArgv)
 {
   NS_ASSERTION(!mImmutable, "Something went wrong ...");
   NS_ENSURE_TRUE(!mImmutable, NS_ERROR_UNEXPECTED);
 
   if (aArgc < 2) {
     return NS_ERROR_TYPE_ERR;
   }
 
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -15,102 +15,98 @@
 #define NS_DOMMULTIPARTBLOB_CID { 0x47bf0b43, 0xf37e, 0x49ef, \
   { 0x81, 0xa0, 0x18, 0xba, 0xc0, 0x57, 0xb5, 0xcc } }
 #define NS_DOMMULTIPARTBLOB_CONTRACTID "@mozilla.org/dom/multipart-blob;1"
 
 #define NS_DOMMULTIPARTFILE_CID { 0xc3361f77, 0x60d1, 0x4ea9, \
   { 0x94, 0x96, 0xdf, 0x5d, 0x6f, 0xcd, 0xd7, 0x8f } }
 #define NS_DOMMULTIPARTFILE_CONTRACTID "@mozilla.org/dom/multipart-file;1"
 
-class nsDOMMultipartFile : public nsDOMFile,
-                           public nsIJSNativeInitializer
+class DOMMultipartFileImpl MOZ_FINAL : public mozilla::dom::DOMFileImplBase
 {
 public:
   // Create as a file
-  nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> > aBlobs,
-                     const nsAString& aName,
-                     const nsAString& aContentType)
-    : nsDOMFile(aName, aContentType, UINT64_MAX),
+  DOMMultipartFileImpl(const nsTArray<nsCOMPtr<nsIDOMBlob>>& aBlobs,
+                       const nsAString& aName,
+                       const nsAString& aContentType)
+    : mozilla::dom::DOMFileImplBase(aName, aContentType, UINT64_MAX),
       mBlobs(aBlobs),
       mIsFromNsiFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a blob
-  nsDOMMultipartFile(nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
-                     const nsAString& aContentType)
-    : nsDOMFile(aContentType, UINT64_MAX),
+  DOMMultipartFileImpl(const nsTArray<nsCOMPtr<nsIDOMBlob>>& aBlobs,
+                       const nsAString& aContentType)
+    : mozilla::dom::DOMFileImplBase(aContentType, UINT64_MAX),
       mBlobs(aBlobs),
       mIsFromNsiFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
-  nsDOMMultipartFile(const nsAString& aName)
-    : nsDOMFile(aName, EmptyString(), UINT64_MAX),
+  explicit DOMMultipartFileImpl(const nsAString& aName)
+    : mozilla::dom::DOMFileImplBase(aName, EmptyString(), UINT64_MAX),
       mIsFromNsiFile(false)
   {
   }
 
   // Create as a blob to be later initialized
-  nsDOMMultipartFile()
-    : nsDOMFile(EmptyString(), UINT64_MAX),
+  DOMMultipartFileImpl()
+    : mozilla::dom::DOMFileImplBase(EmptyString(), UINT64_MAX),
       mIsFromNsiFile(false)
   {
   }
 
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // nsIJSNativeInitializer
-  NS_IMETHOD Initialize(nsISupports* aOwner,
-                        JSContext* aCx,
-                        JSObject* aObj,
-                        const JS::CallArgs& aArgs) MOZ_OVERRIDE;
+  virtual nsresult
+  Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
+             const JS::CallArgs& aArgs) MOZ_OVERRIDE;
 
   typedef nsIDOMBlob* (*UnwrapFuncPtr)(JSContext*, JSObject*);
   nsresult InitBlob(JSContext* aCx,
                     uint32_t aArgc,
                     JS::Value* aArgv,
                     UnwrapFuncPtr aUnwrapFunc);
   nsresult InitFile(JSContext* aCx,
                     uint32_t aArgc,
                     JS::Value* aArgv);
   nsresult InitChromeFile(JSContext* aCx,
                           uint32_t aArgc,
                           JS::Value* aArgv);
 
-  already_AddRefed<nsIDOMBlob>
-  CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) MOZ_OVERRIDE;
+  virtual already_AddRefed<nsIDOMBlob>
+  CreateSlice(uint64_t aStart, uint64_t aLength,
+              const nsAString& aContentType) MOZ_OVERRIDE;
 
-  NS_IMETHOD GetSize(uint64_t*) MOZ_OVERRIDE;
-  NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
+  virtual nsresult GetSize(uint64_t* aSize) MOZ_OVERRIDE;
 
-  static nsresult
-  NewFile(const nsAString& aName, nsISupports* *aNewObject);
+  virtual nsresult GetInternalStream(nsIInputStream** aInputStream) MOZ_OVERRIDE;
+
+  static nsresult NewFile(const nsAString& aName, nsISupports** aNewObject);
 
   // DOMClassInfo constructor (for Blob([b1, "foo"], { type: "image/png" }))
-  static nsresult
-  NewBlob(nsISupports* *aNewObject);
+  static nsresult NewBlob(nsISupports* *aNewObject);
 
   // DOMClassInfo constructor (for File([b1, "foo"], { type: "image/png",
   //                                                   name: "foo.png" }))
-  inline static nsresult
-  NewFile(nsISupports* *aNewObject)
+  inline static nsresult NewFile(nsISupports** aNewObject)
   {
     // Initialization will set the filename, so we can pass in an empty string
     // for now.
     return NewFile(EmptyString(), aNewObject);
   }
 
-  virtual const nsTArray<nsCOMPtr<nsIDOMBlob> >*
-  GetSubBlobs() const MOZ_OVERRIDE { return &mBlobs; }
+  virtual const nsTArray<nsCOMPtr<nsIDOMBlob>>* GetSubBlobs() const MOZ_OVERRIDE
+  {
+    return &mBlobs;
+  }
 
-  NS_IMETHOD GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
 
 protected:
   nsresult ParseBlobArrayArgument(JSContext* aCx, JS::Value& aValue,
                                   bool aNativeEOL, UnwrapFuncPtr aUnwrapFunc);
 
   void SetLengthAndModifiedDate();
 
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
@@ -134,18 +130,18 @@ public:
   nsresult AppendArrayBuffer(JSObject* aBuffer);
   nsresult AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob);
 
   nsTArray<nsCOMPtr<nsIDOMBlob> >& GetBlobs() { Flush(); return mBlobs; }
 
   already_AddRefed<nsIDOMBlob>
   GetBlobInternal(const nsACString& aContentType)
   {
-    nsCOMPtr<nsIDOMBlob> blob =
-      new nsDOMMultipartFile(GetBlobs(), NS_ConvertASCIItoUTF16(aContentType));
+    nsCOMPtr<nsIDOMBlob> blob = new mozilla::dom::DOMFile(
+      new DOMMultipartFileImpl(GetBlobs(), NS_ConvertASCIItoUTF16(aContentType)));
     return blob.forget();
   }
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
   {
     using mozilla::CheckedUint32;
 
@@ -174,17 +170,17 @@ protected:
   }
 
   void Flush() {
     if (mData) {
       // If we have some data, create a blob for it
       // and put it on the stack
 
       nsCOMPtr<nsIDOMBlob> blob =
-        new nsDOMMemoryFile(mData, mDataLen, EmptyString());
+        mozilla::dom::DOMFile::CreateMemoryFile(mData, mDataLen, EmptyString());
       mBlobs.AppendElement(blob);
       mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
       mDataLen = 0;
       mDataBufferLen = 0;
     }
   }
 
   nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -18,43 +18,48 @@
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsIMemoryReporter.h"
 #include "nsIMIMEService.h"
 #include "nsISeekableStream.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIUnicodeDecoder.h"
+#include "nsIRemoteBlob.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIUUIDGenerator.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsStringStream.h"
 #include "nsJSUtils.h"
 #include "nsPrintfCString.h"
 #include "mozilla/SHA1.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/FileListBinding.h"
-using namespace mozilla;
-using namespace mozilla::dom;
+
+DOMCI_DATA(File, mozilla::dom::DOMFile)
+DOMCI_DATA(Blob, mozilla::dom::DOMFile)
+
+namespace mozilla {
+namespace dom {
 
 // XXXkhuey the input stream that we pass out of a DOMFile
 // can outlive the actual DOMFile object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
                                    public nsISeekableStream,
                                    public nsIIPCSerializableInputStream
 {
-  typedef nsDOMMemoryFile::DataOwner DataOwner;
+  typedef DOMFileImplMemory::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          uint32_t aStart,
                          uint32_t aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
@@ -113,96 +118,239 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// nsDOMFileBase implementation
+// mozilla::dom::DOMFile implementation
+
+NS_INTERFACE_MAP_BEGIN(DOMFile)
+  // This class should not receive any nsIRemoteBlob QI!
+  MOZ_ASSERT(!aIID.Equals(NS_GET_IID(nsIRemoteBlob)));
+
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
+  NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
+  NS_INTERFACE_MAP_ENTRY(nsIMutable)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, IsFile())
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !(IsFile()))
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(DOMFile)
+NS_IMPL_RELEASE(DOMFile)
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
+                uint64_t aLength, uint64_t aLastModifiedDate)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplBase(aName, aContentType, aLength, aLastModifiedDate));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Create(const nsAString& aName, const nsAString& aContentType,
+                uint64_t aLength)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplBase(aName, aContentType, aLength));
+  return file.forget();
+}
 
-NS_IMETHODIMP
-nsDOMFileBase::GetName(nsAString &aFileName)
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Create(const nsAString& aContentType, uint64_t aLength)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplBase(aContentType, aLength));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::Create(const nsAString& aContentType, uint64_t aStart,
+                uint64_t aLength)
 {
-  NS_ASSERTION(mIsFile, "Should only be called on files");
-  aFileName = mName;
-  return NS_OK;
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplBase(aContentType, aStart, aLength));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+                          const nsAString& aName,
+                          const nsAString& aContentType,
+                          uint64_t aLastModifiedDate)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplMemory(aMemoryBuffer, aLength, aName,
+                          aContentType, aLastModifiedDate));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateMemoryFile(void* aMemoryBuffer, uint64_t aLength,
+                          const nsAString& aContentType)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplMemory(aMemoryBuffer, aLength, aContentType));
+  return file.forget();
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetPath(nsAString &aPath)
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateTemporaryFileBlob(PRFileDesc* aFD, uint64_t aStartPos,
+                                 uint64_t aLength,
+                                      const nsAString& aContentType)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplTemporaryFileBlob(aFD, aStartPos, aLength, aContentType));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateFromFile(nsIFile* aFile)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateFromFile(const nsAString& aContentType, uint64_t aLength,
+                        nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
 {
-  NS_ASSERTION(mIsFile, "Should only be called on files");
-  aPath = mPath;
-  return NS_OK;
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplFile(aContentType, aLength, aFile, aFileInfo));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateFromFile(const nsAString& aName,
+                        const nsAString& aContentType,
+                        uint64_t aLength, nsIFile* aFile,
+                        indexedDB::FileInfo* aFileInfo)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplFile(aName, aContentType, aLength, aFile, aFileInfo));
+  return file.forget();
+}
+
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateFromFile(nsIFile* aFile, indexedDB::FileInfo* aFileInfo)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(new DOMFileImplFile(aFile, aFileInfo));
+  return file.forget();
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetLastModifiedDate(JSContext* cx, JS::MutableHandle<JS::Value> aLastModifiedDate)
+/* static */ already_AddRefed<DOMFile>
+DOMFile::CreateFromFile(nsIFile* aFile, const nsAString& aName,
+                        const nsAString& aContentType)
+{
+  nsRefPtr<DOMFile> file = new DOMFile(
+    new DOMFileImplFile(aFile, aName, aContentType));
+  return file.forget();
+}
+
+////////////////////////////////////////////////////////////////////////////
+// mozilla::dom::DOMFileBase implementation
+
+const nsTArray<nsCOMPtr<nsIDOMBlob>>*
+DOMFileBase::GetSubBlobs() const
+{
+  return mImpl->GetSubBlobs();
+}
+
+bool
+DOMFileBase::IsSizeUnknown() const
 {
-  JS::Rooted<JSObject*> date(cx, JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC));
-  if (!date) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  aLastModifiedDate.setObject(*date);
-  return NS_OK;
+  return mImpl->IsSizeUnknown();
+}
+
+bool
+DOMFileBase::IsDateUnknown() const
+{
+  return mImpl->IsDateUnknown();
+}
+
+bool
+DOMFileBase::IsFile() const
+{
+  return mImpl->IsFile();
+}
+
+void
+DOMFileBase::SetLazyData(const nsAString& aName, const nsAString& aContentType,
+                         uint64_t aLength, uint64_t aLastModifiedDate)
+{
+  return mImpl->SetLazyData(aName, aContentType, aLength, aLastModifiedDate);
+}
+
+already_AddRefed<nsIDOMBlob>
+DOMFileBase::CreateSlice(uint64_t aStart, uint64_t aLength,
+                         const nsAString& aContentType)
+{
+  return mImpl->CreateSlice(aStart, aLength, aContentType);
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::GetMozFullPath(nsAString &aFileName)
+DOMFileBase::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
+                        const JS::CallArgs& aArgs)
 {
-  NS_ASSERTION(mIsFile, "Should only be called on files");
+  return mImpl->Initialize(aOwner, aCx, aObj, aArgs);
+}
+
+NS_IMETHODIMP
+DOMFileBase::GetName(nsAString& aFileName)
+{
+  return mImpl->GetName(aFileName);
+}
 
-  // It is unsafe to call IsCallerChrome on a non-main thread. If
-  // you hit the following assertion you need to figure out some other way to
-  // determine privileges and call GetMozFullPathInternal.
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+NS_IMETHODIMP
+DOMFileBase::GetPath(nsAString& aPath)
+{
+  return mImpl->GetPath(aPath);
+}
 
-  if (nsContentUtils::IsCallerChrome()) {
-    return GetMozFullPathInternal(aFileName);
-  }
-  aFileName.Truncate();
-  return NS_OK;
+NS_IMETHODIMP
+DOMFileBase::GetLastModifiedDate(JSContext* aCx,
+                                 JS::MutableHandle<JS::Value> aDate)
+{
+  return mImpl->GetLastModifiedDate(aCx, aDate);
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
+DOMFileBase::GetMozFullPath(nsAString &aFileName)
 {
-  if (!mIsFile) {
-    return NS_ERROR_FAILURE;
-  }
+  return mImpl->GetMozFullPath(aFileName);
+}
 
-  aFileName.Truncate();
-  return NS_OK;
+NS_IMETHODIMP
+DOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
+{
+  return mImpl->GetMozFullPathInternal(aFileName);
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::GetSize(uint64_t *aSize)
+DOMFileBase::GetSize(uint64_t* aSize)
 {
-  *aSize = mLength;
-  return NS_OK;
+  return mImpl->GetSize(aSize);
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::GetType(nsAString &aType)
+DOMFileBase::GetType(nsAString &aType)
 {
-  aType = mContentType;
-  return NS_OK;
+  return mImpl->GetType(aType);
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+DOMFileBase::GetMozLastModifiedDate(uint64_t* aDate)
 {
-  NS_ASSERTION(mIsFile, "Should only be called on files");
-  if (IsDateUnknown()) {
-    mLastModificationDate = PR_Now();
-  }
-  *aLastModifiedDate = mLastModificationDate;
-  return NS_OK;
+  return mImpl->GetMozLastModifiedDate(aDate);
 }
 
 // Makes sure that aStart and aEnd is less then or equal to aSize and greater
 // than 0
 static void
 ParseSize(int64_t aSize, int64_t& aStart, int64_t& aEnd)
 {
   CheckedInt64 newStartOffset = aStart;
@@ -233,68 +381,226 @@ ParseSize(int64_t aSize, int64_t& aStart
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
 NS_IMETHODIMP
-nsDOMFileBase::Slice(int64_t aStart, int64_t aEnd,
-                     const nsAString& aContentType, uint8_t optional_argc,
-                     nsIDOMBlob **aBlob)
+DOMFileBase::Slice(int64_t aStart, int64_t aEnd,
+                   const nsAString& aContentType, uint8_t aArgc,
+                   nsIDOMBlob **aBlob)
+{
+  MOZ_ASSERT(mImpl);
+  return mImpl->Slice(aStart, aEnd, aContentType, aArgc, aBlob);
+}
+
+NS_IMETHODIMP
+DOMFileBase::GetInternalStream(nsIInputStream** aStream)
+{
+ return mImpl->GetInternalStream(aStream);
+}
+
+NS_IMETHODIMP
+DOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
+{
+  return mImpl->GetInternalUrl(aPrincipal, aURL);
+}
+
+NS_IMETHODIMP_(int64_t)
+DOMFileBase::GetFileId()
+{
+  return mImpl->GetFileId();
+}
+
+NS_IMETHODIMP_(void)
+DOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+{
+  mImpl->AddFileInfo(aFileInfo);
+}
+
+indexedDB::FileInfo*
+DOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
+{
+  return mImpl->GetFileInfo(aFileManager);
+}
+
+NS_IMETHODIMP
+DOMFileBase::GetSendInfo(nsIInputStream** aBody,
+                         uint64_t* aContentLength,
+                         nsACString& aContentType,
+                         nsACString& aCharset)
+{
+  return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
+}
+
+NS_IMETHODIMP
+DOMFileBase::GetMutable(bool* aMutable)
+{
+  return mImpl->GetMutable(aMutable);
+}
+
+NS_IMETHODIMP
+DOMFileBase::SetMutable(bool aMutable)
+{
+  return mImpl->SetMutable(aMutable);
+}
+
+NS_IMETHODIMP_(bool)
+DOMFileBase::IsMemoryFile()
+{
+  return mImpl->IsMemoryFile();
+}
+
+////////////////////////////////////////////////////////////////////////////
+// mozilla::dom::DOMFileImpl implementation
+
+nsresult
+DOMFileImpl::Slice(int64_t aStart, int64_t aEnd,
+                   const nsAString& aContentType, uint8_t aArgc,
+                   nsIDOMBlob **aBlob)
 {
   *aBlob = nullptr;
 
   // Truncate aStart and aEnd so that we stay within this file.
   uint64_t thisLength;
   nsresult rv = GetSize(&thisLength);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (optional_argc < 2) {
+  if (aArgc < 2) {
     aEnd = (int64_t)thisLength;
   }
 
   ParseSize((int64_t)thisLength, aStart, aEnd);
-  
+
   // Create the new file
-  *aBlob = CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart),
-                       aContentType).take();
+  nsCOMPtr<nsIDOMBlob> blob =
+    CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart), aContentType);
 
+  blob.forget(aBlob);
   return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetInternalStream(nsIInputStream **aStream)
+////////////////////////////////////////////////////////////////////////////
+// DOMFileImplBase implementation
+
+nsresult
+DOMFileImplBase::GetName(nsAString& aName)
+{
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+  aName = mName;
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetPath(nsAString& aPath)
+{
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+  aPath = mPath;
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetLastModifiedDate(JSContext* aCx,
+                                     JS::MutableHandle<JS::Value> aDate)
+{
+  JS::Rooted<JSObject*> date(aCx, JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC));
+  if (!date) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  aDate.setObject(*date);
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetMozFullPath(nsAString &aFileName)
 {
-  // Must be overridden
-  NS_NOTREACHED("Must override GetInternalStream");
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+
+  // It is unsafe to call IsCallerChrome on a non-main thread. If
+  // you hit the following assertion you need to figure out some other way to
+  // determine privileges and call GetMozFullPathInternal.
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (nsContentUtils::IsCallerChrome()) {
+    return GetMozFullPathInternal(aFileName);
+  }
+  aFileName.Truncate();
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetMozFullPathInternal(nsAString& aFileName)
+{
+  if (!mIsFile) {
+    return NS_ERROR_FAILURE;
+  }
+
+  aFileName.Truncate();
+  return NS_OK;
+}
 
+nsresult
+DOMFileImplBase::GetSize(uint64_t* aSize)
+{
+  *aSize = mLength;
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetType(nsAString& aType)
+{
+  aType = mContentType;
+  return NS_OK;
+}
+
+nsresult
+DOMFileImplBase::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+{
+  NS_ASSERTION(mIsFile, "Should only be called on files");
+  if (IsDateUnknown()) {
+    mLastModificationDate = PR_Now();
+  }
+  *aLastModifiedDate = mLastModificationDate;
+  return NS_OK;
+}
+
+already_AddRefed<nsIDOMBlob>
+DOMFileImplBase::CreateSlice(uint64_t aStart, uint64_t aLength,
+                             const nsAString& aContentType)
+{
+  return nullptr;
+}
+
+nsresult
+DOMFileImplBase::GetInternalStream(nsIInputStream** aStream)
+{
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
+nsresult
+DOMFileImplBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
 {
   NS_ENSURE_STATE(aPrincipal);
 
   nsCString url;
   nsresult rv = nsBlobProtocolHandler::AddDataEntry(
-    NS_LITERAL_CSTRING(BLOBURI_SCHEME),
-    static_cast<nsIDOMBlob*>(this), aPrincipal, url);
+    NS_LITERAL_CSTRING(BLOBURI_SCHEME), this, aPrincipal, url);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   CopyASCIItoUTF16(url, aURL);
   return NS_OK;
 }
 
-NS_IMETHODIMP_(int64_t)
-nsDOMFileBase::GetFileId()
+int64_t
+DOMFileImplBase::GetFileId()
 {
   int64_t id = -1;
 
   if (IsStoredFile() && IsWholeFile() && !IsSnapshot()) {
     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
       indexedDB::IndexedDatabaseManager::FileMutex().Lock();
     }
 
@@ -309,18 +615,18 @@ nsDOMFileBase::GetFileId()
     if (!indexedDB::IndexedDatabaseManager::IsClosed()) {
       indexedDB::IndexedDatabaseManager::FileMutex().Unlock();
     }
   }
 
   return id;
 }
 
-NS_IMETHODIMP_(void)
-nsDOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+void
+DOMFileImplBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
 {
   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
     NS_ERROR("Shouldn't be called after shutdown!");
     return;
   }
 
   nsRefPtr<indexedDB::FileInfo> fileInfo = aFileInfo;
 
@@ -328,18 +634,18 @@ nsDOMFileBase::AddFileInfo(indexedDB::Fi
 
   NS_ASSERTION(!mFileInfos.Contains(aFileInfo),
                "Adding the same file info agan?!");
 
   nsRefPtr<indexedDB::FileInfo>* element = mFileInfos.AppendElement();
   element->swap(fileInfo);
 }
 
-NS_IMETHODIMP_(indexedDB::FileInfo*)
-nsDOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
+indexedDB::FileInfo*
+DOMFileImplBase::GetFileInfo(indexedDB::FileManager* aFileManager)
 {
   if (indexedDB::IndexedDatabaseManager::IsClosed()) {
     NS_ERROR("Shouldn't be called after shutdown!");
     return nullptr;
   }
 
   // A slice created from a stored file must keep the file info alive.
   // However, we don't support sharing of slices yet, so the slice must be
@@ -360,21 +666,21 @@ nsDOMFileBase::GetFileInfo(indexedDB::Fi
     if (fileInfo->Manager() == aFileManager) {
       return fileInfo;
     }
   }
 
   return nullptr;
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetSendInfo(nsIInputStream** aBody,
-                           uint64_t* aContentLength,
-                           nsACString& aContentType,
-                           nsACString& aCharset)
+nsresult
+DOMFileImplBase::GetSendInfo(nsIInputStream** aBody,
+                             uint64_t* aContentLength,
+                             nsACString& aContentType,
+                             nsACString& aCharset)
 {
   nsresult rv;
 
   nsCOMPtr<nsIInputStream> stream;
   rv = this->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = this->GetSize(aContentLength);
@@ -387,25 +693,25 @@ nsDOMFileBase::GetSendInfo(nsIInputStrea
   CopyUTF16toUTF8(contentType, aContentType);
 
   aCharset.Truncate();
 
   stream.forget(aBody);
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::GetMutable(bool* aMutable)
+nsresult
+DOMFileImplBase::GetMutable(bool* aMutable) const
 {
   *aMutable = !mImmutable;
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMFileBase::SetMutable(bool aMutable)
+nsresult
+DOMFileImplBase::SetMutable(bool aMutable)
 {
   nsresult rv = NS_OK;
 
   NS_ENSURE_ARG(!mImmutable || !aMutable);
 
   if (!mImmutable && !aMutable) {
     // Force the content type and size to be cached
     nsString dummyString;
@@ -416,133 +722,115 @@ nsDOMFileBase::SetMutable(bool aMutable)
     rv = this->GetSize(&dummyInt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mImmutable = !aMutable;
   return rv;
 }
 
-NS_IMETHODIMP_(bool)
-nsDOMFileBase::IsMemoryFile(void)
-{
-  return false;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// nsDOMFile implementation
-
-DOMCI_DATA(File, nsDOMFile)
-DOMCI_DATA(Blob, nsDOMFile)
-
-NS_INTERFACE_MAP_BEGIN(nsDOMFile)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
-  NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
-  NS_INTERFACE_MAP_ENTRY(nsIMutable)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
-NS_INTERFACE_MAP_END
-
-// Threadsafe when GetMutable() == false
-NS_IMPL_ADDREF(nsDOMFile)
-NS_IMPL_RELEASE(nsDOMFile)
+NS_IMPL_ISUPPORTS0(DOMFileImplBase)
 
 ////////////////////////////////////////////////////////////////////////////
-// nsDOMFileCC implementation
+// DOMFileCC implementation
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileCC)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMFileCC)
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsDOMFileCC)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileCC)
-  // We don't have anything to traverse, but some of our subclasses do.
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMFileCC)
+  tmp->mImpl->Unlink();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMFileCC)
+  tmp->mImpl->Traverse(cb);
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileCC)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMFileCC)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, IsFile())
   NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
   NS_INTERFACE_MAP_ENTRY(nsIMutable)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, mIsFile)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !mIsFile)
+  NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(File, IsFile())
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(Blob, !(IsFile()))
 NS_INTERFACE_MAP_END
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileCC)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileCC)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMFileCC)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMFileCC)
 
 ////////////////////////////////////////////////////////////////////////////
-// nsDOMFileFile implementation
+// DOMFileImplFile implementation
 
 already_AddRefed<nsIDOMBlob>
-nsDOMFileFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                           const nsAString& aContentType)
+DOMFileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
+                             const nsAString& aContentType)
 {
-  nsCOMPtr<nsIDOMBlob> t = new nsDOMFileFile(this, aStart, aLength, aContentType);
-  return t.forget();
+  nsCOMPtr<nsIDOMBlob> blob =
+    new DOMFile(new DOMFileImplFile(this, aStart, aLength, aContentType));
+  return blob.forget();
 }
 
-NS_IMETHODIMP
-nsDOMFileFile::GetMozFullPathInternal(nsAString &aFilename)
+nsresult
+DOMFileImplFile::GetMozFullPathInternal(nsAString& aFilename)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   return mFile->GetPath(aFilename);
 }
 
-NS_IMETHODIMP
-nsDOMFileFile::GetLastModifiedDate(JSContext* cx, JS::MutableHandle<JS::Value> aLastModifiedDate)
+nsresult
+DOMFileImplFile::GetLastModifiedDate(JSContext* aCx,
+                                     JS::MutableHandle<JS::Value> aLastModifiedDate)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
   PRTime msecs;
   if (IsDateUnknown()) {
     nsresult rv = mFile->GetLastModifiedTime(&msecs);
     NS_ENSURE_SUCCESS(rv, rv);
     mLastModificationDate = msecs;
   } else {
     msecs = mLastModificationDate;
   }
 
-  JSObject* date = JS_NewDateObjectMsec(cx, msecs);
+  JSObject* date = JS_NewDateObjectMsec(aCx, msecs);
   if (date) {
     aLastModifiedDate.setObject(*date);
   }
   else {
-    date = JS_NewDateObjectMsec(cx, JS_Now() / PR_USEC_PER_MSEC);
+    date = JS_NewDateObjectMsec(aCx, JS_Now() / PR_USEC_PER_MSEC);
     aLastModifiedDate.setObject(*date);
   }
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMFileFile::GetSize(uint64_t *aFileSize)
+nsresult
+DOMFileImplFile::GetSize(uint64_t* aFileSize)
 {
   if (IsSizeUnknown()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy size when using the whole file");
     int64_t fileSize;
     nsresult rv = mFile->GetFileSize(&fileSize);
     NS_ENSURE_SUCCESS(rv, rv);
-  
+
     if (fileSize < 0) {
       return NS_ERROR_FAILURE;
     }
-  
+
     mLength = fileSize;
   }
 
   *aFileSize = mLength;
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMFileFile::GetType(nsAString &aType)
+nsresult
+DOMFileImplFile::GetType(nsAString& aType)
 {
   if (mContentType.IsVoid()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy ContentType when using the whole file");
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -557,18 +845,18 @@ nsDOMFileFile::GetType(nsAString &aType)
     mContentType.SetIsVoid(false);
   }
 
   aType = mContentType;
 
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsDOMFileFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
+nsresult
+DOMFileImplFile::GetMozLastModifiedDate(uint64_t* aLastModifiedDate)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   if (IsDateUnknown()) {
     PRTime msecs;
     nsresult rv = mFile->GetLastModifiedTime(&msecs);
     NS_ENSURE_SUCCESS(rv, rv);
     mLastModificationDate = msecs;
   }
@@ -576,84 +864,78 @@ nsDOMFileFile::GetMozLastModifiedDate(ui
   return NS_OK;
 }
 
 const uint32_t sFileStreamFlags =
   nsIFileInputStream::CLOSE_ON_EOF |
   nsIFileInputStream::REOPEN_ON_REWIND |
   nsIFileInputStream::DEFER_OPEN;
 
-NS_IMETHODIMP
-nsDOMFileFile::GetInternalStream(nsIInputStream **aStream)
+nsresult
+DOMFileImplFile::GetInternalStream(nsIInputStream** aStream)
 {
   return mWholeFile ?
     NS_NewLocalFileInputStream(aStream, mFile, -1, -1, sFileStreamFlags) :
     NS_NewPartialLocalFileInputStream(aStream, mFile, mStart, mLength,
                                       -1, -1, sFileStreamFlags);
 }
 
 void
-nsDOMFileFile::SetPath(const nsAString& aPath)
+DOMFileImplFile::SetPath(const nsAString& aPath)
 {
   MOZ_ASSERT(aPath.IsEmpty() ||
              aPath[aPath.Length() - 1] == char16_t('/'),
              "Path must end with a path separator");
   mPath = aPath;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// nsDOMMemoryFile implementation
+// DOMFileImplMemory implementation
 
 already_AddRefed<nsIDOMBlob>
-nsDOMMemoryFile::CreateSlice(uint64_t aStart, uint64_t aLength,
-                             const nsAString& aContentType)
+DOMFileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
+                               const nsAString& aContentType)
 {
-  nsCOMPtr<nsIDOMBlob> t =
-    new nsDOMMemoryFile(this, aStart, aLength, aContentType);
-  return t.forget();
+  nsCOMPtr<nsIDOMBlob> blob =
+    new DOMFile(new DOMFileImplMemory(this, aStart, aLength, aContentType));
+  return blob.forget();
 }
 
-NS_IMETHODIMP
-nsDOMMemoryFile::GetInternalStream(nsIInputStream **aStream)
+nsresult
+DOMFileImplMemory::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX)
     return NS_ERROR_FAILURE;
 
   return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
 }
 
-NS_IMETHODIMP_(bool)
-nsDOMMemoryFile::IsMemoryFile(void)
-{
-  return true;
-}
+/* static */ StaticMutex
+DOMFileImplMemory::DataOwner::sDataOwnerMutex;
 
-/* static */ StaticMutex
-nsDOMMemoryFile::DataOwner::sDataOwnerMutex;
-
-/* static */ StaticAutoPtr<LinkedList<nsDOMMemoryFile::DataOwner> >
-nsDOMMemoryFile::DataOwner::sDataOwners;
+/* static */ StaticAutoPtr<LinkedList<DOMFileImplMemory::DataOwner>>
+DOMFileImplMemory::DataOwner::sDataOwners;
 
 /* static */ bool
-nsDOMMemoryFile::DataOwner::sMemoryReporterRegistered;
+DOMFileImplMemory::DataOwner::sMemoryReporterRegistered = false;
 
 MOZ_DEFINE_MALLOC_SIZE_OF(DOMMemoryFileDataOwnerMallocSizeOf)
 
-class nsDOMMemoryFileDataOwnerMemoryReporter MOZ_FINAL
+class DOMFileImplMemoryDataOwnerMemoryReporter MOZ_FINAL
   : public nsIMemoryReporter
 {
-  ~nsDOMMemoryFileDataOwnerMemoryReporter() {}
+  ~DOMFileImplMemoryDataOwnerMemoryReporter() {}
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIMemoryReporterCallback *aCallback,
                             nsISupports *aClosure, bool aAnonymize)
   {
-    typedef nsDOMMemoryFile::DataOwner DataOwner;
+    typedef DOMFileImplMemory::DataOwner DataOwner;
 
     StaticMutexAutoLock lock(DataOwner::sDataOwnerMutex);
 
     if (!DataOwner::sDataOwners) {
       return NS_OK;
     }
 
     const size_t LARGE_OBJECT_MIN_SIZE = 8 * 1024;
@@ -708,49 +990,77 @@ public:
         aClosure);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     return NS_OK;
   }
 };
 
-NS_IMPL_ISUPPORTS(nsDOMMemoryFileDataOwnerMemoryReporter, nsIMemoryReporter)
+NS_IMPL_ISUPPORTS(DOMFileImplMemoryDataOwnerMemoryReporter, nsIMemoryReporter)
 
 /* static */ void
-nsDOMMemoryFile::DataOwner::EnsureMemoryReporterRegistered()
+DOMFileImplMemory::DataOwner::EnsureMemoryReporterRegistered()
 {
   sDataOwnerMutex.AssertCurrentThreadOwns();
   if (sMemoryReporterRegistered) {
     return;
   }
 
-  RegisterStrongMemoryReporter(new nsDOMMemoryFileDataOwnerMemoryReporter());
+  RegisterStrongMemoryReporter(new DOMFileImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
+// DOMFileImplTemporaryFileBlob implementation
+
+already_AddRefed<nsIDOMBlob>
+DOMFileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
+                                          const nsAString& aContentType)
+{
+  if (aStart + aLength > mLength)
+    return nullptr;
+
+  nsCOMPtr<nsIDOMBlob> blob =
+    new DOMFile(new DOMFileImplTemporaryFileBlob(this, aStart + mStartPos,
+                                                 aLength, aContentType));
+  return blob.forget();
+}
+
+nsresult
+DOMFileImplTemporaryFileBlob::GetInternalStream(nsIInputStream** aStream)
+{
+  nsCOMPtr<nsIInputStream> stream =
+    new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
+  stream.forget(aStream);
+  return NS_OK;
+}
+
+} // dom namespace
+} // mozilla namespace
+
+////////////////////////////////////////////////////////////////////////////
 // nsDOMFileList implementation
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
 
 JSObject*
 nsDOMFileList::WrapObject(JSContext *cx)
 {
-  return FileListBinding::Wrap(cx, this);
+  return mozilla::dom::FileListBinding::Wrap(cx, this);
 }
 
 NS_IMETHODIMP
 nsDOMFileList::GetLength(uint32_t* aLength)
 {
   *aLength = Length();
 
   return NS_OK;
@@ -776,31 +1086,8 @@ nsDOMFileInternalUrlHolder::nsDOMFileInt
  
 nsDOMFileInternalUrlHolder::~nsDOMFileInternalUrlHolder() {
   if (!mUrl.IsEmpty()) {
     nsAutoCString narrowUrl;
     CopyUTF16toUTF8(mUrl, narrowUrl);
     nsBlobProtocolHandler::RemoveDataEntry(narrowUrl);
   }
 }
-
-////////////////////////////////////////////////////////////////////////////
-// nsDOMTemporaryFileBlob implementation
-already_AddRefed<nsIDOMBlob>
-nsDOMTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
-                                    const nsAString& aContentType)
-{
-  if (aStart + aLength > mLength)
-    return nullptr;
-
-  nsCOMPtr<nsIDOMBlob> t =
-    new nsDOMTemporaryFileBlob(this, aStart + mStartPos, aLength, aContentType);
-  return t.forget();
-}
-
-NS_IMETHODIMP
-nsDOMTemporaryFileBlob::GetInternalStream(nsIInputStream **aStream)
-{
-  nsCOMPtr<nsIInputStream> stream =
-    new nsTemporaryFileInputStream(mFileDescOwner, mStartPos, mStartPos + mLength);
-  stream.forget(aStream);
-  return NS_OK;
-}
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -878,16 +878,17 @@ GK_ATOM(parentapp, "parentapp")
 GK_ATOM(parentfocused, "parentfocused")
 GK_ATOM(parsetype, "parsetype")
 GK_ATOM(pattern, "pattern")
 GK_ATOM(patternSeparator, "pattern-separator")
 GK_ATOM(perMille, "per-mille")
 GK_ATOM(percent, "percent")
 GK_ATOM(persist, "persist")
 GK_ATOM(phase, "phase")
+GK_ATOM(picture, "picture")
 GK_ATOM(ping, "ping")
 GK_ATOM(pinned,"pinned")
 GK_ATOM(placeholder, "placeholder")
 GK_ATOM(plaintext, "plaintext")
 GK_ATOM(playbackrate, "playbackrate")
 GK_ATOM(pointSize, "point-size")
 GK_ATOM(poly, "poly")
 GK_ATOM(polygon, "polygon")
@@ -2215,17 +2216,16 @@ GK_ATOM(marginBottom, "margin-bottom")
 GK_ATOM(marginLeft, "margin-left")
 GK_ATOM(marginRight, "margin-right")
 GK_ATOM(marginTop, "margin-top")
 GK_ATOM(menuitemcheckbox, "menuitemcheckbox")
 GK_ATOM(menuitemradio, "menuitemradio")
 GK_ATOM(mixed, "mixed")
 GK_ATOM(multiline, "multiline")
 GK_ATOM(password, "password")
-GK_ATOM(picture, "picture")
 GK_ATOM(posinset, "posinset")
 GK_ATOM(presentation, "presentation")
 GK_ATOM(progressbar, "progressbar")
 GK_ATOM(region, "region")
 GK_ATOM(rowgroup, "rowgroup")
 GK_ATOM(rowheader, "rowheader")
 GK_ATOM(select1, "select1")
 GK_ATOM(setsize, "setsize")
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1166,17 +1166,27 @@ nsXMLHttpRequest::GetStatusText(nsCStrin
   }
 
   // Make sure we don't leak status information from denied cross-site
   // requests.
   if (IsDeniedCrossSiteRequest()) {
     return;
   }
 
-  httpChannel->GetResponseStatusText(aStatusText);
+
+  // Check the current XHR state to see if it is valid to obtain the statusText
+  // value.  This check is to prevent the status text for redirects from being
+  // available before all the redirects have been followed and HTTP headers have
+  // been received.
+  uint16_t readyState;
+  GetReadyState(&readyState);
+  if (readyState != OPENED && readyState != UNSENT) {
+    httpChannel->GetResponseStatusText(aStatusText);
+  }
+
 
 }
 
 void
 nsXMLHttpRequest::CloseRequestWithError(const nsAString& aType,
                                         const uint32_t aFlag)
 {
   if (mChannel) {
@@ -1859,17 +1869,19 @@ bool nsXMLHttpRequest::CreateDOMFile(nsI
 
   if (!file)
     return false;
 
   nsAutoCString contentType;
   mChannel->GetContentType(contentType);
 
   mDOMFile =
-    new nsDOMFileFile(file, EmptyString(), NS_ConvertASCIItoUTF16(contentType));
+    DOMFile::CreateFromFile(file, EmptyString(),
+                            NS_ConvertASCIItoUTF16(contentType));
+
   mBlobSet = nullptr;
   NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
   return true;
 }
 
 NS_IMETHODIMP
 nsXMLHttpRequest::OnDataAvailable(nsIRequest *request,
                                   nsISupports *ctxt,
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -47,16 +47,20 @@ class nsDOMFile;
 class nsFormData;
 class nsIJARChannel;
 class nsILoadGroup;
 class nsIUnicodeDecoder;
 class nsIJSID;
 
 namespace mozilla {
 
+namespace dom {
+class DOMFile;
+}
+
 // A helper for building up an ArrayBuffer object's data
 // before creating the ArrayBuffer itself.  Will do doubling
 // based reallocation, up to an optional maximum growth given.
 //
 // When all the data has been appended, call getArrayBuffer,
 // passing in the JSContext* for which the ArrayBuffer object
 // is to be created.  This also implicitly resets the builder,
 // or it can be reset explicitly at any point by calling reset().
@@ -662,17 +666,17 @@ protected:
 
   ResponseTypeEnum mResponseType;
 
   // It is either a cached blob-response from the last call to GetResponse,
   // but is also explicitly set in OnStopRequest.
   nsCOMPtr<nsIDOMBlob> mResponseBlob;
   // Non-null only when we are able to get a os-file representation of the
   // response, i.e. when loading from a file.
-  nsRefPtr<nsDOMFile> mDOMFile;
+  nsRefPtr<mozilla::dom::DOMFile> mDOMFile;
   // We stream data to mBlobSet when response type is "blob" or "moz-blob"
   // and mDOMFile is null.
   nsAutoPtr<BlobSet> mBlobSet;
 
   nsString mOverrideMimeType;
 
   /**
    * The notification callbacks the channel had when Send() was
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug1011748_OK.sjs
@@ -0,0 +1,4 @@
+// Function to indicate HTTP 200 OK after redirect from file_bug1011748_redirect.sjs
+function handleRequest(request, response) {
+  response.setStatusLine(null, 200, "OK");
+}
new file mode 100644
--- /dev/null
+++ b/content/base/test/file_bug1011748_redirect.sjs
@@ -0,0 +1,5 @@
+// SJS handler to redirect the XMLHttpRequest object to file_bug1011748_OK.sjs
+function handleRequest(request, response) {
+  response.setStatusLine(null, 302, "Moved Temporarily");
+  response.setHeader("Location", "file_bug1011748_OK.sjs", false);
+}
--- a/content/base/test/mochitest.ini
+++ b/content/base/test/mochitest.ini
@@ -641,8 +641,11 @@ skip-if = toolkit == 'android'
 [test_file_from_blob.html]
 [test_warning_for_blocked_cross_site_request.html]
 [test_bug444546.html]
 disabled = Disabled for now. Mochitest isn't reliable enough for these.
 support-files = bug444546.sjs
 [test_bug503473.html]
 disabled = Disabled due to making the harness time out
 support-files = file_bug503473-frame.sjs
+[test_bug1011748.html]
+skip-if = buildapp == 'b2g' || e10s
+support-files = file_bug1011748_redirect.sjs file_bug1011748_OK.sjs
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug1011748.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1011748
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1011748</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /** Test for Bug 1011748 **/
+  "use strict";
+  
+  var observer = {
+    observe: function (aSubject, aTopic, aData) {
+      try {
+        var channel = aSubject.QueryInterface(SpecialPowers.Ci.nsIHttpChannel);
+        channel.getResponseHeader("Location");
+      } catch (e) {
+        return;
+      }
+      statusTexts.push(xhr.statusText);
+    }
+  };
+  
+  var statusTexts = [];
+  SpecialPowers.addObserver(observer, "http-on-examine-response", false);
+  SimpleTest.waitForExplicitFinish();
+  var xhr = new XMLHttpRequest();
+  xhr.addEventListener("load", function() {
+    statusTexts.push(this.statusText);
+    SpecialPowers.removeObserver(observer, "http-on-examine-response");
+    is(statusTexts[0], "", "Empty statusText value for HTTP 302");
+    is(statusTexts[1], "OK", "OK statusText value for the redirect."); 
+    SimpleTest.finish();
+  });
+  xhr.open("GET", "file_bug1011748_redirect.sjs", true);
+  xhr.send();
+  
+
+
+
+
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1011748">Mozilla Bug 1011748</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/content/canvas/src/CanvasImageCache.cpp
+++ b/content/canvas/src/CanvasImageCache.cpp
@@ -113,16 +113,17 @@ public:
   nsTHashtable<ImageCacheEntry> mCache;
   size_t mTotal;
 };
 
 static ImageCache* gImageCache = nullptr;
 
 class CanvasImageCacheShutdownObserver MOZ_FINAL : public nsIObserver
 {
+  ~CanvasImageCacheShutdownObserver() {}
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 };
 
 void
 CanvasImageCache::NotifyDrawImage(Element* aImage,
                                   HTMLCanvasElement* aCanvas,
--- a/content/canvas/src/CanvasPattern.h
+++ b/content/canvas/src/CanvasPattern.h
@@ -19,16 +19,17 @@ namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
 class SVGMatrix;
 
 class CanvasPattern MOZ_FINAL : public nsWrapperCache
 {
+  ~CanvasPattern() {}
 public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPattern)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPattern)
 
   MOZ_BEGIN_NESTED_ENUM_CLASS(RepeatMode, uint8_t)
     REPEAT,
     REPEATX,
     REPEATY,
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -140,16 +140,17 @@ const Float SIGMA_MAX = 100;
 /* Memory reporter stuff */
 static int64_t gCanvasAzureMemoryUsed = 0;
 
 // This is KIND_OTHER because it's not always clear where in memory the pixels
 // of a canvas are stored.  Furthermore, this memory will be tracked by the
 // underlying surface implementations.  See bug 655638 for details.
 class Canvas2dPixelsReporter MOZ_FINAL : public nsIMemoryReporter
 {
+  ~Canvas2dPixelsReporter() {}
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                             nsISupports* aData, bool aAnonymize)
   {
     return MOZ_COLLECT_REPORT(
       "canvas-2d-pixels", KIND_OTHER, UNITS_BYTES,
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -88,19 +88,19 @@ public:
   TemporaryRef<gfx::Path> GetPath(const CanvasWindingRule& aWinding,
                                   const gfx::DrawTarget* aTarget) const;
 
   explicit CanvasPath(nsISupports* aParent);
   // TemporaryRef arg because the return value from Path::CopyToBuilder() is
   // passed directly and we can't drop the only ref to have a raw pointer.
   CanvasPath(nsISupports* aParent,
              TemporaryRef<gfx::PathBuilder> aPathBuilder);
-  virtual ~CanvasPath() {}
 
 private:
+  virtual ~CanvasPath() {}
 
   nsCOMPtr<nsISupports> mParent;
   static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
 
   mutable RefPtr<gfx::Path> mPath;
   mutable RefPtr<gfx::PathBuilder> mPathBuilder;
 
   void EnsurePathBuilder() const;
@@ -114,19 +114,20 @@ class CanvasRenderingContext2DUserData;
  **/
 class CanvasRenderingContext2D :
   public nsICanvasRenderingContextInternal,
   public nsWrapperCache
 {
 typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
   HTMLImageOrCanvasOrVideoElement;
 
+  virtual ~CanvasRenderingContext2D();
+
 public:
   CanvasRenderingContext2D();
-  virtual ~CanvasRenderingContext2D();
 
   virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
   HTMLCanvasElement* GetCanvas() const
   {
     // corresponds to changes to the old bindings made in bug 745025
     return mCanvasElement->GetOriginalCanvas();
   }
--- a/content/canvas/src/ImageData.h
+++ b/content/canvas/src/ImageData.h
@@ -18,32 +18,32 @@
 #include "nsISupportsImpl.h"
 #include "js/GCAPI.h"
 
 namespace mozilla {
 namespace dom {
 
 class ImageData MOZ_FINAL : public nsISupports
 {
+  ~ImageData()
+  {
+    MOZ_COUNT_DTOR(ImageData);
+    DropData();
+  }
+
 public:
   ImageData(uint32_t aWidth, uint32_t aHeight, JSObject& aData)
     : mWidth(aWidth)
     , mHeight(aHeight)
     , mData(&aData)
   {
     MOZ_COUNT_CTOR(ImageData);
     HoldData();
   }
 
-  ~ImageData()
-  {
-    MOZ_COUNT_DTOR(ImageData);
-    DropData();
-  }
-
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageData)
 
   static ImageData* Constructor(const GlobalObject& aGlobal,
                                 const uint32_t aWidth,
                                 const uint32_t aHeight,
                                 ErrorResult& aRv);
 
--- a/content/canvas/src/ImageEncoder.cpp
+++ b/content/canvas/src/ImageEncoder.cpp
@@ -11,41 +11,42 @@
 
 using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace dom {
 
 class EncodingCompleteEvent : public nsRunnable
 {
+  virtual ~EncodingCompleteEvent() {}
+
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   EncodingCompleteEvent(nsIScriptContext* aScriptContext,
                         nsIThread* aEncoderThread,
                         FileCallback& aCallback)
     : mImgSize(0)
     , mType()
     , mImgData(nullptr)
     , mScriptContext(aScriptContext)
     , mEncoderThread(aEncoderThread)
     , mCallback(&aCallback)
     , mFailed(false)
   {}
-  virtual ~EncodingCompleteEvent() {}
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
     mozilla::ErrorResult rv;
 
     if (!mFailed) {
-      nsRefPtr<nsDOMMemoryFile> blob =
-        new nsDOMMemoryFile(mImgData, mImgSize, mType);
+      nsRefPtr<DOMFile> blob =
+        DOMFile::CreateMemoryFile(mImgData, mImgSize, mType);
 
       if (mScriptContext) {
         JSContext* jsContext = mScriptContext->GetNativeContext();
         if (jsContext) {
           JS_updateMallocCounter(jsContext, mImgSize);
         }
       }
 
@@ -84,16 +85,18 @@ private:
   nsRefPtr<FileCallback> mCallback;
   bool mFailed;
 };
 
 NS_IMPL_ISUPPORTS(EncodingCompleteEvent, nsIRunnable);
 
 class EncodingRunnable : public nsRunnable
 {
+  virtual ~EncodingRunnable() {}
+
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   EncodingRunnable(const nsAString& aType,
                    const nsAString& aOptions,
                    uint8_t* aImageBuffer,
                    imgIEncoder* aEncoder,
                    EncodingCompleteEvent* aEncodingCompleteEvent,
@@ -104,17 +107,16 @@ public:
     , mOptions(aOptions)
     , mImageBuffer(aImageBuffer)
     , mEncoder(aEncoder)
     , mEncodingCompleteEvent(aEncodingCompleteEvent)
     , mFormat(aFormat)
     , mSize(aSize)
     , mUsingCustomOptions(aUsingCustomOptions)
   {}
-  virtual ~EncodingRunnable() {}
 
   nsresult ProcessImageData(uint64_t* aImgSize, void** aImgData)
   {
     nsCOMPtr<nsIInputStream> stream;
     nsresult rv = ImageEncoder::ExtractDataInternal(mType,
                                                     mOptions,
                                                     mImageBuffer,
                                                     mFormat,
--- a/content/canvas/src/WebGLBuffer.h
+++ b/content/canvas/src/WebGLBuffer.h
@@ -21,18 +21,16 @@ class WebGLBuffer MOZ_FINAL
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
     , public WebGLContextBoundObject
 {
 public:
     WebGLBuffer(WebGLContext *context);
 
-    ~WebGLBuffer();
-
     void Delete();
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
     GLuint GLName() const { return mGLName; }
     WebGLsizeiptr ByteLength() const { return mByteLength; }
@@ -56,16 +54,17 @@ public:
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
 
 protected:
+    ~WebGLBuffer();
 
     GLuint mGLName;
     bool mHasEverBeenBound;
     WebGLsizeiptr mByteLength;
     GLenum mTarget;
 
     nsAutoPtr<WebGLElementArrayCache> mCache;
 };
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -157,17 +157,16 @@ class WebGLContext :
         UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
         BROWSER_DEFAULT_WEBGL = 0x9244,
         UNMASKED_VENDOR_WEBGL = 0x9245,
         UNMASKED_RENDERER_WEBGL = 0x9246
     };
 
 public:
     WebGLContext();
-    virtual ~WebGLContext();
 
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(WebGLContext,
                                                            nsIDOMWebGLRenderingContext)
 
     virtual JSObject* WrapObject(JSContext *cx) = 0;
 
@@ -877,16 +876,18 @@ private:
     void VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength, const GLfloat* ptr);
 
     bool ValidateBufferFetching(const char *info);
     bool BindArrayAttribToLocation0(WebGLProgram *program);
 
 // -----------------------------------------------------------------------------
 // PROTECTED
 protected:
+    virtual ~WebGLContext();
+
     void SetFakeBlackStatus(WebGLContextFakeBlackStatus x) {
         mFakeBlackStatus = x;
     }
     // Returns the current fake-black-status, except if it was Unknown,
     // in which case this function resolves it first, so it never returns Unknown.
     WebGLContextFakeBlackStatus ResolvedFakeBlackStatus();
 
     void BindFakeBlackTextures();
--- a/content/canvas/src/WebGLExtensions.h
+++ b/content/canvas/src/WebGLExtensions.h
@@ -19,28 +19,29 @@ class WebGLShader;
 class WebGLVertexArray;
 
 class WebGLExtensionBase
     : public nsWrapperCache
     , public WebGLContextBoundObject
 {
 public:
     WebGLExtensionBase(WebGLContext*);
-    virtual ~WebGLExtensionBase();
 
     WebGLContext *GetParentObject() const {
         return Context();
     }
 
     void MarkLost();
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLExtensionBase)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLExtensionBase)
 
 protected:
+    virtual ~WebGLExtensionBase();
+
     bool mIsLost;
 };
 
 #define DECL_WEBGL_EXTENSION_GOOP                                           \
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
 #define IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionType) \
     JSObject* \
--- a/content/canvas/src/WebGLFramebuffer.h
+++ b/content/canvas/src/WebGLFramebuffer.h
@@ -25,20 +25,16 @@ class WebGLFramebuffer MOZ_FINAL
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
     , public WebGLContextBoundObject
 {
 public:
     WebGLFramebuffer(WebGLContext* context);
 
-    ~WebGLFramebuffer() {
-        DeleteOnce();
-    }
-
     struct Attachment
     {
         // deleting a texture or renderbuffer immediately detaches it
         WebGLRefPtr<WebGLTexture> mTexturePtr;
         WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
         GLenum mAttachmentPoint;
         GLenum mTexImageTarget;
         GLint mTexImageLevel;
@@ -176,16 +172,20 @@ public:
     bool CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const;
 
     void EnsureColorAttachments(size_t colorAttachmentId);
 
     Attachment* AttachmentFor(GLenum attachment);
     void NotifyAttachableChanged() const;
 
 private:
+    ~WebGLFramebuffer() {
+        DeleteOnce();
+    }
+
     mutable GLenum mStatus;
 
     GLuint mGLName;
     bool mHasEverBeenBound;
 
     // we only store pointers to attached renderbuffers, not to attached textures, because
     // we will only need to initialize renderbuffers. Textures are already initialized.
     nsTArray<Attachment> mColorAttachments;
--- a/content/canvas/src/WebGLMemoryTracker.h
+++ b/content/canvas/src/WebGLMemoryTracker.h
@@ -20,17 +20,16 @@
 namespace mozilla {
 
 class WebGLMemoryTracker : public nsIMemoryReporter
 {
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIMEMORYREPORTER
 
     WebGLMemoryTracker();
-    virtual ~WebGLMemoryTracker();
     static StaticRefPtr<WebGLMemoryTracker> sUniqueInstance;
 
     // Here we store plain pointers, not RefPtrs: we don't want the
     // WebGLMemoryTracker unique instance to keep alive all
     // WebGLContexts ever created.
     typedef nsTArray<const WebGLContext*> ContextsArrayType;
     ContextsArrayType mContexts;
 
@@ -52,16 +51,18 @@ class WebGLMemoryTracker : public nsIMem
         ContextsArrayType & contexts = Contexts();
         contexts.RemoveElement(c);
         if (contexts.IsEmpty()) {
             sUniqueInstance = nullptr;
         }
     }
 
   private:
+    virtual ~WebGLMemoryTracker();
+
     static int64_t GetTextureMemoryUsed() {
         const ContextsArrayType & contexts = Contexts();
         int64_t result = 0;
         for(size_t i = 0; i < contexts.Length(); ++i) {
             for (const WebGLTexture *texture = contexts[i]->mTextures.getFirst();
                  texture;
                  texture = texture->getNext())
             {
--- a/content/canvas/src/WebGLProgram.h
+++ b/content/canvas/src/WebGLProgram.h
@@ -28,20 +28,16 @@ class WebGLProgram MOZ_FINAL
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLProgram>
     , public LinkedListElement<WebGLProgram>
     , public WebGLContextBoundObject
 {
 public:
     WebGLProgram(WebGLContext *context);
 
-    ~WebGLProgram() {
-        DeleteOnce();
-    }
-
     void Delete();
 
     void DetachShaders() {
         mAttachedShaders.Clear();
     }
 
     GLuint GLName() { return mGLName; }
     const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; }
@@ -110,16 +106,19 @@ public:
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
 
     // public post-link data
     std::map<GLint, nsCString> mActiveAttribMap;
 
 protected:
+    ~WebGLProgram() {
+        DeleteOnce();
+    }
 
     GLuint mGLName;
     bool mLinkStatus;
     // attached shaders of the program object
     nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
     CheckedUint32 mGeneration;
 
     // post-link data
--- a/content/canvas/src/WebGLQuery.h
+++ b/content/canvas/src/WebGLQuery.h
@@ -20,25 +20,20 @@ class WebGLQuery MOZ_FINAL
     , public LinkedListElement<WebGLQuery>
     , public WebGLContextBoundObject
 {
 // -----------------------------------------------------------------------------
 // PUBLIC
 public:
 
     // -------------------------------------------------------------------------
-    // CONSTRUCTOR & DESTRUCTOR
+    // CONSTRUCTOR
 
     WebGLQuery(WebGLContext *context);
 
-    ~WebGLQuery() {
-        DeleteOnce();
-    };
-
-
     // -------------------------------------------------------------------------
     // MEMBER FUNCTIONS
 
     bool IsActive() const;
 
     bool HasEverBeenActive()
     {
         return mType != 0;
@@ -62,16 +57,19 @@ public:
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQuery)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLQuery)
 
 
 // -----------------------------------------------------------------------------
 // PRIVATE
 private:
+    ~WebGLQuery() {
+        DeleteOnce();
+    };
 
     // -------------------------------------------------------------------------
     // MEMBERS
     GLuint mGLName;
     GLenum mType;
 
     // -------------------------------------------------------------------------
     // FRIENDSHIPS
--- a/content/canvas/src/WebGLRenderbuffer.h
+++ b/content/canvas/src/WebGLRenderbuffer.h
@@ -21,20 +21,16 @@ class WebGLRenderbuffer MOZ_FINAL
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     WebGLRenderbuffer(WebGLContext *context);
 
-    ~WebGLRenderbuffer() {
-        DeleteOnce();
-    }
-
     void Delete();
 
     bool HasEverBeenBound() { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
 
     bool HasUninitializedImageData() const { return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData; }
     void SetImageDataStatus(WebGLImageDataStatus x) {
         // there is no way to go from having image data to not having any
@@ -62,16 +58,20 @@ public:
     GLint GetRenderbufferParameter(GLenum target, GLenum pname) const;
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
 
 protected:
+    ~WebGLRenderbuffer() {
+        DeleteOnce();
+    }
+
     GLuint mPrimaryRB;
     GLuint mSecondaryRB;
     GLenum mInternalFormat;
     GLenum mInternalFormatForGL;
     bool mHasEverBeenBound;
     WebGLImageDataStatus mImageDataStatus;
 
     friend class WebGLFramebuffer;
--- a/content/canvas/src/WebGLShader.h
+++ b/content/canvas/src/WebGLShader.h
@@ -30,20 +30,16 @@ class WebGLShader MOZ_FINAL
     , public WebGLContextBoundObject
 {
     friend class WebGLContext;
     friend class WebGLProgram;
 
 public:
     WebGLShader(WebGLContext *context, GLenum stype);
 
-    ~WebGLShader() {
-        DeleteOnce();
-    }
-
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
     GLuint GLName() { return mGLName; }
     GLenum ShaderType() { return mType; }
 
     void SetSource(const nsAString& src) {
         // XXX do some quick gzip here maybe -- getting this will be very rare
         mSource.Assign(src);
@@ -79,16 +75,19 @@ public:
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
 
 protected:
+    ~WebGLShader() {
+        DeleteOnce();
+    }
 
     GLuint mGLName;
     GLenum mType;
     nsString mSource;
     nsString mTranslatedSource;
     nsCString mTranslationLog; // The translation log should contain only ASCII characters
     bool mNeedsTranslation;
     nsTArray<WebGLMappedIdentifier> mAttributes;
--- a/content/canvas/src/WebGLTexture.h
+++ b/content/canvas/src/WebGLTexture.h
@@ -30,20 +30,16 @@ class WebGLTexture MOZ_FINAL
     , public WebGLRefCountedObject<WebGLTexture>
     , public LinkedListElement<WebGLTexture>
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     WebGLTexture(WebGLContext *context);
 
-    ~WebGLTexture() {
-        DeleteOnce();
-    }
-
     void Delete();
 
     bool HasEverBeenBound() const { return mHasEverBeenBound; }
     void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
     GLuint GLName() const { return mGLName; }
     GLenum Target() const { return mTarget; }
 
     WebGLContext *GetParentObject() const {
@@ -51,16 +47,19 @@ public:
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
 
 protected:
+    ~WebGLTexture() {
+        DeleteOnce();
+    }
 
     friend class WebGLContext;
     friend class WebGLFramebuffer;
 
     bool mHasEverBeenBound;
     GLuint mGLName;
 
     // we store information about the various images that are part of
--- a/content/canvas/src/WebGLUniformLocation.h
+++ b/content/canvas/src/WebGLUniformLocation.h
@@ -14,19 +14,16 @@ namespace mozilla {
 class WebGLProgram;
 
 class WebGLUniformLocation MOZ_FINAL
     : public WebGLContextBoundObject
 {
 public:
     WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location, const WebGLUniformInfo& info);
 
-    ~WebGLUniformLocation() {
-    }
-
     // needed for certain helper functions like ValidateObject.
     // WebGLUniformLocation's can't be 'Deleted' in the WebGL sense.
     bool IsDeleted() const { return false; }
 
     const WebGLUniformInfo &Info() const { return mInfo; }
 
     WebGLProgram *Program() const { return mProgram; }
     GLint Location() const { return mLocation; }
@@ -34,16 +31,19 @@ public:
     int ElementSize() const { return mElementSize; }
 
     JSObject* WrapObject(JSContext *cx);
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
     NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
 
 protected:
+    ~WebGLUniformLocation() {
+    }
+
     // nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
     // we just want to avoid having a dangling pointer.
     nsRefPtr<WebGLProgram> mProgram;
 
     uint32_t mProgramGeneration;
     GLint mLocation;
     WebGLUniformInfo mInfo;
     int mElementSize;
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -609,18 +609,19 @@ HTMLCanvasElement::MozGetAsFileImpl(cons
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   if (cx) {
     JS_updateMallocCounter(cx, imgSize);
   }
 
   // The DOMFile takes ownership of the buffer
-  nsRefPtr<nsDOMMemoryFile> file =
-    new nsDOMMemoryFile(imgData, (uint32_t)imgSize, aName, type, PR_Now());
+  nsRefPtr<DOMFile> file =
+    DOMFile::CreateMemoryFile(imgData, (uint32_t)imgSize, aName, type,
+                              PR_Now());
 
   file.forget(aResult);
   return NS_OK;
 }
 
 nsresult
 HTMLCanvasElement::GetContextHelper(const nsAString& aContextId,
                                     nsICanvasRenderingContextInternal **aContext)
--- a/content/html/content/src/HTMLInputElement.cpp
+++ b/content/html/content/src/HTMLInputElement.cpp
@@ -369,30 +369,33 @@ public:
   {
     MOZ_ASSERT(!NS_IsMainThread(),
                "Walking the directory tree involves I/O, so using this "
                "enumerator can block a thread for a long time!");
 
     if (!mNextFile) {
       return NS_ERROR_FAILURE;
     }
-    nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(mNextFile);
+    nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(mNextFile);
     nsCString relDescriptor;
     nsresult rv =
       mNextFile->GetRelativeDescriptor(mTopDirsParent, relDescriptor);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ConvertUTF8toUTF16 path(relDescriptor);
     nsAutoString leafName;
     mNextFile->GetLeafName(leafName);
     MOZ_ASSERT(leafName.Length() <= path.Length());
     int32_t length = path.Length() - leafName.Length();
     MOZ_ASSERT(length >= 0);
     if (length > 0) {
       // Note that we leave the trailing "/" on the path.
-      domFile->SetPath(Substring(path, 0, uint32_t(length)));
+      DOMFileImplFile* fileImpl =
+        static_cast<DOMFileImplFile*>(domFile->Impl());
+      MOZ_ASSERT(fileImpl);
+      fileImpl->SetPath(Substring(path, 0, uint32_t(length)));
     }
     *aResult = domFile.forget().downcast<nsIDOMFile>().take();
     LookupAndCacheNext();
     return NS_OK;
   }
 
   NS_IMETHOD
   HasMoreElements(bool* aResult)
@@ -2313,17 +2316,17 @@ HTMLInputElement::MozSetFileNameArray(co
     }
 
     if (!file) {
       // this is no "file://", try as local file
       NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
     }
 
     if (file) {
-      nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(file);
+      nsCOMPtr<nsIDOMFile> domFile = DOMFile::CreateFromFile(file);
       files.AppendElement(domFile);
     } else {
       continue; // Not much we can do if the file doesn't exist
     }
 
   }
 
   SetFiles(files, true);
--- a/content/html/content/src/moz.build
+++ b/content/html/content/src/moz.build
@@ -172,17 +172,17 @@ LOCAL_INCLUDES += [
     '/content/canvas/src',
     '/content/html/document/src',
     '/content/media/',
     '/content/xul/content/src',
     '/dom/base',
     '/dom/xbl',
     '/editor/libeditor/base',
     '/editor/libeditor/text',
-    '/editor/txmgr/src',
+    '/editor/txmgr',
     '/layout/forms',
     '/layout/generic',
     '/layout/style',
     '/layout/tables',
     '/layout/xul',
     '/netwerk/base/src',
 ]
 
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -109,43 +109,41 @@ DownmixAndInterleave(const nsTArray<cons
   if (channelData.Length() > aOutputChannels) {
     AudioChannelsDownMix(channelData, outputChannelBuffers.Elements(),
                          aOutputChannels, aDuration);
   }
   InterleaveAndConvertBuffer(outputChannelData.Elements(), AUDIO_FORMAT_FLOAT32,
                              aDuration, aVolume, aOutputChannels, aOutput);
 }
 
-void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler)
+void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler, uint32_t aInRate, uint32_t aOutRate)
 {
-  uint32_t inRate, outRate;
-
   if (mChunks.IsEmpty()) {
     return;
   }
 
-  speex_resampler_get_rate(aResampler, &inRate, &outRate);
+  MOZ_ASSERT(aResampler || IsNull(), "We can only be here without a resampler if this segment is null.");
 
   AudioSampleFormat format = AUDIO_FORMAT_SILENCE;
   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     if (ci->mBufferFormat != AUDIO_FORMAT_SILENCE) {
       format = ci->mBufferFormat;
     }
   }
 
   switch (format) {
     // If the format is silence at this point, all the chunks are silent. The
     // actual function we use does not matter, it's just a matter of changing
     // the chunks duration.
     case AUDIO_FORMAT_SILENCE:
     case AUDIO_FORMAT_FLOAT32:
-      Resample<float>(aResampler, inRate, outRate);
+      Resample<float>(aResampler, aInRate, aOutRate);
     break;
     case AUDIO_FORMAT_S16:
-      Resample<int16_t>(aResampler, inRate, outRate);
+      Resample<int16_t>(aResampler, aInRate, aOutRate);
     break;
     default:
       MOZ_ASSERT(false);
     break;
   }
 }
 
 void
--- a/content/media/AudioSegment.h
+++ b/content/media/AudioSegment.h
@@ -220,17 +220,19 @@ public:
       c.mBuffer = new mozilla::SharedChannelArrayBuffer<T>(&output);
       for (uint32_t i = 0; i < channels; i++) {
         c.mChannelData[i] = bufferPtrs[i];
       }
       mDuration += c.mDuration;
     }
   }
 
-  void ResampleChunks(SpeexResamplerState* aResampler);
+  void ResampleChunks(SpeexResamplerState* aResampler,
+                      uint32_t aInRate,
+                      uint32_t aOutRate);
 
   void AppendFrames(already_AddRefed<ThreadSharedObject> aBuffer,
                     const nsTArray<const float*>& aChannelData,
                     int32_t aDuration)
   {
     AudioChunk* chunk = AppendChunk(aDuration);
     chunk->mBuffer = aBuffer;
     for (uint32_t channel = 0; channel < aChannelData.Length(); ++channel) {
@@ -282,16 +284,25 @@ public:
     for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
       if (ci->ChannelCount()) {
         return ci->ChannelCount();
       }
     }
     return 0;
   }
 
+  bool IsNull() {
+    for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
+      if (!ci->IsNull()) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   static Type StaticType() { return AUDIO; }
 
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
   {
     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   }
 };
 
--- a/content/media/EncodedBufferCache.cpp
+++ b/content/media/EncodedBufferCache.cpp
@@ -41,33 +41,33 @@ EncodedBufferCache::AppendBuffer(nsTArra
 
 already_AddRefed<nsIDOMBlob>
 EncodedBufferCache::ExtractBlob(const nsAString &aContentType)
 {
   MutexAutoLock lock(mMutex);
   nsCOMPtr<nsIDOMBlob> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
-    blob = new nsDOMTemporaryFileBlob(mFD, 0, mDataSize, aContentType);
+    blob = dom::DOMFile::CreateTemporaryFileBlob(mFD, 0, mDataSize,
+                                                 aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
   } else {
     void* blobData = moz_malloc(mDataSize);
     NS_ASSERTION(blobData, "out of memory!!");
 
     if (blobData) {
       for (uint32_t i = 0, offset = 0; i < mEncodedBuffers.Length(); i++) {
         memcpy((uint8_t*)blobData + offset, mEncodedBuffers.ElementAt(i).Elements(),
                mEncodedBuffers.ElementAt(i).Length());
         offset += mEncodedBuffers.ElementAt(i).Length();
       }
-      blob = new nsDOMMemoryFile(blobData, mDataSize,
-                                 aContentType);
+      blob = dom::DOMFile::CreateMemoryFile(blobData, mDataSize, aContentType);
       mEncodedBuffers.Clear();
     } else
       return nullptr;
   }
   mDataSize = 0;
   return blob.forget();
 }
 
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2291,17 +2291,17 @@ SourceMediaStream::ResampleAudioToGraphS
         return;
       }
       aTrackData->mResampler.own(state);
 #ifdef DEBUG
       aTrackData->mResamplerChannelCount = channels;
 #endif
     }
   }
-  segment->ResampleChunks(aTrackData->mResampler);
+  segment->ResampleChunks(aTrackData->mResampler, aTrackData->mInputRate, GraphImpl()->AudioSampleRate());
 }
 
 bool
 SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegment *aRawSegment)
 {
   MutexAutoLock lock(mMutex);
   // ::EndAllTrackAndFinished() can end these before the sources notice
   bool appended = false;
new file mode 100644
--- /dev/null
+++ b/content/media/test/crashtests/1028458.html
@@ -0,0 +1,21 @@
+<html class="reftest-wait">
+<audio id="testAudio" controls></audio>
+<script type="text/javascript">
+navigator.mozGetUserMedia({audio: true}, function(stream) {
+    stream.getAudioTracks()[0].enabled = false;
+    var testAudio = document.getElementById('testAudio');
+    // Wait some time for good measure
+    var eventReceived = 0;
+    testAudio.addEventListener("timeupdate", function() {
+      if (++eventReceived == 3) {
+        document.querySelector("html").className = "";
+      }
+    })
+    testAudio.mozSrcObject = stream;
+    testAudio.play();
+    }, function(err) {
+    console.log(err);
+    });
+</script>
+
+</html>
--- a/content/media/test/crashtests/crashtests.list
+++ b/content/media/test/crashtests/crashtests.list
@@ -67,8 +67,9 @@ load 952756.html
 load 986901.html
 load buffer-source-ended-1.html
 load offline-buffer-source-ended-1.html
 HTTP load media-element-source-seek-1.html
 skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338
 skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338
 load 1015662.html
 include ../../mediasource/test/crashtests/crashtests.list
+test-pref(media.navigator.permission.disabled,true) load 1028458.html
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -203,17 +203,17 @@ MediaEngineDefaultVideoSource::Snapshot(
   nsCOMPtr<nsIFile> localFile;
   filePicker->GetFile(getter_AddRefs(localFile));
 
   if (!localFile) {
     *aFile = nullptr;
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(localFile);
+  nsCOMPtr<nsIDOMFile> domFile = dom::DOMFile::CreateFromFile(localFile);
   domFile.forget(aFile);
   return NS_OK;
 #endif
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
 {
--- a/content/media/webrtc/MediaEngineWebRTC.h
+++ b/content/media/webrtc/MediaEngineWebRTC.h
@@ -214,17 +214,17 @@ private:
   void Init();
   void Shutdown();
 
   // Engine variables.
 #ifdef MOZ_B2G_CAMERA
   mozilla::ReentrantMonitor mCallbackMonitor; // Monitor for camera callback handling
   // This is only modified on MainThread (AllocImpl and DeallocImpl)
   nsRefPtr<ICameraControl> mCameraControl;
-  nsRefPtr<nsIDOMFile> mLastCapture;
+  nsCOMPtr<nsIDOMFile> mLastCapture;
 
   // These are protected by mMonitor below
   int mRotation;
   int mCameraAngle; // See dom/base/ScreenOrientation.h
   bool mBackCamera;
 #else
   webrtc::VideoEngine* mVideoEngine; // Weak reference, don't free.
   webrtc::ViEBase* mViEBase;
--- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp
+++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp
@@ -826,20 +826,19 @@ MediaEngineWebRTCVideoSource::OnUserErro
   ReentrantMonitorAutoEnter sync(mCallbackMonitor);
   mCallbackMonitor.Notify();
 }
 
 void
 MediaEngineWebRTCVideoSource::OnTakePictureComplete(uint8_t* aData, uint32_t aLength, const nsAString& aMimeType)
 {
   ReentrantMonitorAutoEnter sync(mCallbackMonitor);
-  mLastCapture =
-    static_cast<nsIDOMFile*>(new nsDOMMemoryFile(static_cast<void*>(aData),
-                                                 static_cast<uint64_t>(aLength),
-                                                 aMimeType));
+  mLastCapture = dom::DOMFile::CreateMemoryFile(static_cast<void*>(aData),
+                                                static_cast<uint64_t>(aLength),
+                                                aMimeType);
   mCallbackMonitor.Notify();
 }
 
 void
 MediaEngineWebRTCVideoSource::RotateImage(layers::Image* aImage, uint32_t aWidth, uint32_t aHeight) {
   layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(aImage);
   android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
   void *pMem = nullptr;
--- a/content/svg/content/src/SVGPathData.h
+++ b/content/svg/content/src/SVGPathData.h
@@ -18,17 +18,16 @@
 #include "nsSVGElement.h"
 #include "nsTArray.h"
 
 #include <string.h>
 
 class gfxContext;
 class nsSVGPathDataParser; // IWYU pragma: keep
 
-struct gfxMatrix;
 struct nsSVGMark;
 
 namespace mozilla {
 
 /**
  * ATTENTION! WARNING! WATCH OUT!!
  *
  * Consumers that modify objects of this type absolutely MUST keep the DOM
--- a/content/svg/content/src/SVGTransform.h
+++ b/content/svg/content/src/SVGTransform.h
@@ -13,17 +13,17 @@
 #include "nsDebug.h"
 #include "nsID.h"
 #include "nsSVGTransform.h"
 #include "nsWrapperCache.h"
 #include "mozilla/Attributes.h"
 
 class nsSVGElement;
 
-struct gfxMatrix;
+class gfxMatrix;
 
 #define MOZ_SVG_LIST_INDEX_BIT_COUNT 31 // supports > 2 billion list items
 
 namespace mozilla {
 namespace dom {
 
 class SVGMatrix;
 
--- a/content/svg/content/src/nsSVGElement.h
+++ b/content/svg/content/src/nsSVGElement.h
@@ -59,17 +59,17 @@ class SVGStringList;
 class DOMSVGStringList;
 
 namespace gfx {
 class Matrix;
 }
 
 }
 
-struct gfxMatrix;
+class gfxMatrix;
 struct nsSVGEnumMapping;
 
 typedef nsStyledElementNotElementCSSInlineStyle nsSVGElementBase;
 
 class nsSVGElement : public nsSVGElementBase    // nsIContent
                    , public nsIDOMSVGElement
 {
 protected:
--- a/content/svg/content/src/nsSVGPathGeometryElement.h
+++ b/content/svg/content/src/nsSVGPathGeometryElement.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
 #define __NS_SVGPATHGEOMETRYELEMENT_H__
 
 #include "mozilla/gfx/2D.h"
 #include "SVGGraphicsElement.h"
 
-struct gfxMatrix;
+class gfxMatrix;
 
 struct nsSVGMark {
   enum Type {
     eStart,
     eMid,
     eEnd,
 
     eTypeCount
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -434,17 +434,21 @@ WebappsApplication.prototype = {
     this._ondownloadapplied = aCallback;
   },
 
   get ondownloadapplied() {
     return this._ondownloadapplied;
   },
 
   get downloadError() {
-    return new this._window.DOMError(this._downloadError || '');
+    // Only return DOMError when we have an error.
+    if (!this._downloadError) {
+      return null;
+    }
+    return new this._window.DOMError(this._downloadError);
   },
 
   download: function() {
     cpmm.sendAsyncMessage("Webapps:Download",
                           { manifestURL: this.manifestURL });
   },
 
   cancelDownload: function() {
@@ -588,17 +592,18 @@ WebappsApplication.prototype = {
 
   _updateState: function(aMsg) {
     if (aMsg.app) {
       for (let prop in aMsg.app) {
         this[prop] = aMsg.app[prop];
       }
     }
 
-    if (aMsg.error) {
+    // Intentional use of 'in' so we unset the error if this is explicitly null.
+    if ('error' in aMsg) {
       this._downloadError = aMsg.error;
     }
 
     if (aMsg.manifest) {
       this._manifest = aMsg.manifest;
       manifestCache.evict(this.manifestURL, this.innerWindowID);
     }
   },
@@ -643,16 +648,22 @@ WebappsApplication.prototype = {
         // The parent might ask childs to trigger more than one event in one
         // shot, so in order to avoid needless IPC we allow an array for the
         // 'eventType' IPC message field.
         if (!Array.isArray(msg.eventType)) {
           msg.eventType = [msg.eventType];
         }
 
         msg.eventType.forEach((aEventType) => {
+          // If we are in a successful state clear any past errors.
+          if (aEventType === 'downloadapplied' ||
+              aEventType === 'downloadsuccess') {
+            this._downloadError = null;
+          }
+
           if ("_on" + aEventType in this) {
             this._fireEvent(aEventType);
           } else {
             dump("Unsupported event type " + aEventType + "\n");
           }
         });
 
         if (req) {
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -1582,16 +1582,18 @@ this.DOMApplicationRegistry = {
     }
 
     // We set the 'downloading' flag and update the apps registry right before
     // starting the app download/update.
     aApp.downloading = true;
     aApp.progress = 0;
     DOMApplicationRegistry._saveApps().then(() => {
       DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
+        // Clear any previous errors.
+        error: null,
         app: {
           downloading: true,
           installState: aApp.installState,
           progress: 0
         },
         manifestURL: aApp.manifestURL
       });
       let cacheUpdate = updateSvc.scheduleAppUpdate(
@@ -2777,16 +2779,18 @@ this.DOMApplicationRegistry = {
 
       // initialize the progress to 0 right now
       oldApp.progress = 0;
 
       // Save the current state of the app to handle cases where we may be
       // retrying a past download.
       yield DOMApplicationRegistry._saveApps();
       DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
+        // Clear any previous download errors.
+        error: null,
         app: oldApp,
         manifestURL: aNewApp.manifestURL
       });
 
       let zipFile = yield this._getPackage(requestChannel, id, oldApp, aNewApp);
       let hash = yield this._computeFileHash(zipFile.path);
 
       let responseStatus = requestChannel.responseStatus;
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -79,21 +79,21 @@ nsIDOMFile*
 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new ArchiveZipFile(filename,
-                            NS_ConvertUTF8toUTF16(GetType()),
-                            StrToInt32(mCentralStruct.orglen),
-                            mCentralStruct,
-                            aArchiveReader);
+  return new DOMFileCC(
+    new ArchiveZipFileImpl(filename,
+                           NS_ConvertUTF8toUTF16(GetType()),
+                           StrToInt32(mCentralStruct.orglen),
+                           mCentralStruct, aArchiveReader));
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
 {
   return (uint32_t)( (aStr [0] <<  0) |
                      (aStr [1] <<  8) |
                      (aStr [2] << 16) |
--- a/dom/archivereader/ArchiveZipFile.cpp
+++ b/dom/archivereader/ArchiveZipFile.cpp
@@ -346,20 +346,20 @@ ArchiveInputStream::Tell(int64_t *aResul
 }
 
 NS_IMETHODIMP
 ArchiveInputStream::SetEOF()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
-// ArchiveZipFile
+// ArchiveZipFileImpl
 
-NS_IMETHODIMP
-ArchiveZipFile::GetInternalStream(nsIInputStream** aStream)
+nsresult
+ArchiveZipFileImpl::GetInternalStream(nsIInputStream** aStream)
 {
   if (mLength > INT32_MAX) {
     return NS_ERROR_FAILURE;
   }
 
   uint64_t size;
   nsresult rv = mArchiveReader->GetSize(&size);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -377,35 +377,33 @@ ArchiveZipFile::GetInternalStream(nsIInp
                                                                mLength,
                                                                mCentral);
   NS_ADDREF(stream);
 
   *aStream = stream;
   return NS_OK;
 }
 
-already_AddRefed<nsIDOMBlob>
-ArchiveZipFile::CreateSlice(uint64_t aStart,
-                            uint64_t aLength,
-                            const nsAString& aContentType)
+void
+ArchiveZipFileImpl::Unlink()
 {
-  nsCOMPtr<nsIDOMBlob> t = new ArchiveZipFile(mFilename,
-                                              mContentType,
-                                              aStart,
-                                              mLength,
-                                              mCentral,
-                                              mArchiveReader);
-  return t.forget();
+  ArchiveZipFileImpl* tmp = this;
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mArchiveReader);
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ArchiveZipFile, nsDOMFileCC,
-                                   mArchiveReader)
+void
+ArchiveZipFileImpl::Traverse(nsCycleCollectionTraversalCallback &cb)
+{
+  ArchiveZipFileImpl* tmp = this;
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mArchiveReader);
+}
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveZipFile)
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFile)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBlob)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIDOMFile, mIsFile)
-  NS_INTERFACE_MAP_ENTRY(nsIXHRSendable)
-  NS_INTERFACE_MAP_ENTRY(nsIMutable)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMFileCC)
-
-NS_IMPL_ADDREF_INHERITED(ArchiveZipFile, nsDOMFileCC)
-NS_IMPL_RELEASE_INHERITED(ArchiveZipFile, nsDOMFileCC)
+already_AddRefed<nsIDOMBlob>
+ArchiveZipFileImpl::CreateSlice(uint64_t aStart,
+                                uint64_t aLength,
+                                const nsAString& aContentType)
+{
+  nsCOMPtr<nsIDOMBlob> t =
+    new DOMFileCC(new ArchiveZipFileImpl(mFilename, mContentType,
+                                         aStart, mLength, mCentral,
+                                         mArchiveReader));
+  return t.forget();
+}
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -13,60 +13,60 @@
 #include "ArchiveReader.h"
 
 #include "ArchiveReaderCommon.h"
 #include "zipstruct.h"
 
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 /**
- * ZipFile to DOMFileCC
+ * ArchiveZipFileImpl to DOMFileImpl
  */
-class ArchiveZipFile : public nsDOMFileCC
+class ArchiveZipFileImpl : public DOMFileImplBase
 {
 public:
-  ArchiveZipFile(const nsAString& aName,
-                 const nsAString& aContentType,
-                 uint64_t aLength,
-                 ZipCentral& aCentral,
-                 ArchiveReader* aReader)
-  : nsDOMFileCC(aName, aContentType, aLength),
+  ArchiveZipFileImpl(const nsAString& aName,
+                     const nsAString& aContentType,
+                     uint64_t aLength,
+                     ZipCentral& aCentral,
+                     ArchiveReader* aReader)
+  : DOMFileImplBase(aName, aContentType, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
-    MOZ_COUNT_CTOR(ArchiveZipFile);
+    MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
-  ArchiveZipFile(const nsAString& aName,
-                 const nsAString& aContentType,
-                 uint64_t aStart,
-                 uint64_t aLength,
-                 ZipCentral& aCentral,
-                 ArchiveReader* aReader)
-  : nsDOMFileCC(aContentType, aStart, aLength),
+  ArchiveZipFileImpl(const nsAString& aName,
+                     const nsAString& aContentType,
+                     uint64_t aStart,
+                     uint64_t aLength,
+                     ZipCentral& aCentral,
+                     ArchiveReader* aReader)
+  : DOMFileImplBase(aContentType, aStart, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
     mFilename(aName)
   {
     NS_ASSERTION(mArchiveReader, "must have a reader");
-    MOZ_COUNT_CTOR(ArchiveZipFile);
+    MOZ_COUNT_CTOR(ArchiveZipFileImpl);
   }
 
-  virtual ~ArchiveZipFile()
+  virtual ~ArchiveZipFileImpl()
   {
-    MOZ_COUNT_DTOR(ArchiveZipFile);
+    MOZ_COUNT_DTOR(ArchiveZipFileImpl);
   }
 
   // Overrides:
-  NS_IMETHOD GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
+  virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
 
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ArchiveZipFile, nsDOMFileCC)
+  virtual void Unlink() MOZ_OVERRIDE;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
 protected:
   virtual already_AddRefed<nsIDOMBlob> CreateSlice(uint64_t aStart,
                                                    uint64_t aLength,
                                                    const nsAString& aContentType) MOZ_OVERRIDE;
 
 private: // Data
   ZipCentral mCentral;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -449,18 +449,18 @@ struct nsConstructorFuncMapData
   nsDOMConstructorFunc mConstructorFunc;
 };
 
 #define NS_DEFINE_CONSTRUCTOR_FUNC_DATA(_class, _func)                        \
   { eDOMClassInfo_##_class##_id, _func },
 
 static const nsConstructorFuncMapData kConstructorFuncMap[] =
 {
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, nsDOMMultipartFile::NewBlob)
-  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, nsDOMMultipartFile::NewFile)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(Blob, DOMMultipartFileImpl::NewBlob)
+  NS_DEFINE_CONSTRUCTOR_FUNC_DATA(File, DOMMultipartFileImpl::NewFile)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(MozSmsFilter, SmsFilter::NewSmsFilter)
   NS_DEFINE_CONSTRUCTOR_FUNC_DATA(XSLTProcessor, XSLTProcessorCtor)
 };
 #undef NS_DEFINE_CONSTRUCTOR_FUNC_DATA
 
 nsIXPConnect *nsDOMClassInfo::sXPConnect = nullptr;
 nsIScriptSecurityManager *nsDOMClassInfo::sSecMan = nullptr;
 bool nsDOMClassInfo::sIsInitialized = false;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2779,17 +2779,18 @@ nsDOMWindowUtils::WrapDOMFile(nsIFile *a
                               nsIDOMFile **aDOMFile)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   if (!aFile) {
     return NS_ERROR_FAILURE;
   }
 
-  NS_ADDREF(*aDOMFile = new nsDOMFileFile(aFile));
+  nsRefPtr<DOMFile> file = DOMFile::CreateFromFile(aFile);
+  file.forget(aDOMFile);
   return NS_OK;
 }
 
 #ifdef DEBUG
 static bool
 CheckLeafLayers(Layer* aLayer, const nsIntPoint& aOffset, nsIntRegion* aCoveredRegion)
 {
   gfx::Matrix transform;
@@ -2954,31 +2955,40 @@ GetFileOrBlob(const nsAString& aName, JS
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsresult rv;
 
   nsCOMPtr<nsISupports> file;
 
   if (aName.IsVoid()) {
-    rv = nsDOMMultipartFile::NewBlob(getter_AddRefs(file));
+    rv = DOMMultipartFileImpl::NewBlob(getter_AddRefs(file));
   }
   else {
-    rv = nsDOMMultipartFile::NewFile(aName, getter_AddRefs(file));
+    rv = DOMMultipartFileImpl::NewFile(aName, getter_AddRefs(file));
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsDOMMultipartFile* domFile =
-    static_cast<nsDOMMultipartFile*>(static_cast<nsIDOMFile*>(file.get()));
+  nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(file);
+  MOZ_ASSERT(blob);
+
+  nsRefPtr<DOMFile> domFile = static_cast<DOMFile*>(blob.get());
+
+  DOMFileImpl* fileImpl = domFile->Impl();
+  MOZ_ASSERT(fileImpl);
+
+  DOMMultipartFileImpl* domFileImpl =
+    static_cast<DOMMultipartFileImpl*>(fileImpl);
 
   JS::AutoValueArray<2> args(aCx);
   args[0].set(aBlobParts);
   args[1].set(aParameters);
 
-  rv = domFile->InitBlob(aCx, aOptionalArgCount, args.begin(), GetXPConnectNative);
+  rv = domFileImpl->InitBlob(aCx, aOptionalArgCount, args.begin(),
+                             GetXPConnectNative);
   NS_ENSURE_SUCCESS(rv, rv);
 
   file.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetFile(const nsAString& aName, JS::Handle<JS::Value> aBlobParts,
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -333,19 +333,20 @@ DOMCameraControlListener::OnTakePictureC
       , mData(aData)
       , mLength(aLength)
       , mMimeType(aMimeType)
     { }
 
     void
     RunCallback(nsDOMCameraControl* aDOMCameraControl) MOZ_OVERRIDE
     {
-      nsCOMPtr<nsIDOMBlob> picture = new nsDOMMemoryFile(static_cast<void*>(mData),
-                                                         static_cast<uint64_t>(mLength),
-                                                         mMimeType);
+      nsCOMPtr<nsIDOMBlob> picture =
+        DOMFile::CreateMemoryFile(static_cast<void*>(mData),
+                                  static_cast<uint64_t>(mLength),
+                                  mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
     }
 
   protected:
     uint8_t* mData;
     uint32_t mLength;
     nsString mMimeType;
   };
--- a/dom/datastore/DataStoreDB.cpp
+++ b/dom/datastore/DataStoreDB.cpp
@@ -112,18 +112,17 @@ DataStoreDB::HandleEvent(nsIDOMEvent* aE
   if (type.EqualsASCII("error") || type.EqualsASCII("blocked")) {
     RemoveEventListeners();
     mState = Inactive;
     mCallback->Run(this, false);
     mRequest = nullptr;
     return NS_OK;
   }
 
-  MOZ_ASSUME_UNREACHABLE("This should not happen");
-  return NS_OK;
+  MOZ_CRASH("This should not happen");
 }
 
 nsresult
 DataStoreDB::UpgradeSchema()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   AutoSafeJSContext cx;
--- a/dom/datastore/DataStoreRevision.cpp
+++ b/dom/datastore/DataStoreRevision.cpp
@@ -48,18 +48,17 @@ DataStoreRevision::AddRevision(JSContext
   data.mObjectId = aObjectId;
 
   switch (aRevisionType) {
     case RevisionVoid:
       data.mOperation = NS_LITERAL_STRING("void");
       break;
 
     default:
-      MOZ_ASSUME_UNREACHABLE("This should not happen");
-      break;
+      MOZ_CRASH("This should not happen");
   }
 
   JS::Rooted<JS::Value> value(aCx);
   if (!ToJSValue(aCx, data, &value)) {
     return NS_ERROR_FAILURE;
   }
 
   ErrorResult error;
@@ -83,18 +82,17 @@ DataStoreRevision::HandleEvent(nsIDOMEve
 {
   nsString type;
   nsresult rv = aEvent->GetType(type);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (!type.EqualsASCII("success")) {
-    MOZ_ASSUME_UNREACHABLE("This should not happen");
-    return NS_ERROR_FAILURE;
+    MOZ_CRASH("This should not happen");
   }
 
   mRequest->RemoveEventListener(NS_LITERAL_STRING("success"), this, false);
   mRequest = nullptr;
 
   mCallback->Run(mRevisionID);
   return NS_OK;
 }
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -517,19 +517,19 @@ nsresult
 DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString mime;
   CopyASCIItoUTF16(mMimeType, mime);
 
   nsString fullPath;
   mFile->GetFullPath(fullPath);
-  nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, mime, mLength, 
-                                                mFile->mFile,
-                                                mLastModificationDate);
+  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+    new DOMFileImplFile(fullPath, mime, mLength, mFile->mFile,
+                        mLastModificationDate));
 
   ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
   BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
   if (!actor) {
     ErrorResponse response(NS_LITERAL_STRING(POST_ERROR_EVENT_UNKNOWN));
     unused << mParent->Send__delete__(mParent, response);
     return NS_OK;
   }
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1709,19 +1709,20 @@ nsIFileToJsval(nsPIDOMWindow* aWindow, D
   aFile->GetFullPath(fullPath);
 
   // This check is useful to know if somewhere the DeviceStorageFile
   // has not been properly set. Mimetype is not checked because it can be
   // empty.
   MOZ_ASSERT(aFile->mLength != UINT64_MAX);
   MOZ_ASSERT(aFile->mLastModifiedDate != UINT64_MAX);
 
-  nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(fullPath, aFile->mMimeType,
-                                                aFile->mLength, aFile->mFile,
-                                                aFile->mLastModifiedDate);
+  nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+    new DOMFileImplFile(fullPath, aFile->mMimeType,
+                        aFile->mLength, aFile->mFile,
+                        aFile->mLastModifiedDate));
   return InterfaceToJsval(aWindow, blob, &NS_GET_IID(nsIDOMBlob));
 }
 
 JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -300,17 +300,17 @@ DataTransfer::GetFiles(ErrorResult& aRv)
       if (NS_FAILED(rv))
         continue;
 
       nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
 
       if (!file)
         continue;
 
-      nsRefPtr<nsDOMFileFile> domFile = new nsDOMFileFile(file);
+      nsRefPtr<DOMFile> domFile = DOMFile::CreateFromFile(file);
 
       if (!mFiles->Append(domFile)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return nullptr;
       }
     }
   }
 
--- a/dom/filehandle/File.cpp
+++ b/dom/filehandle/File.cpp
@@ -10,103 +10,107 @@
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
 
 namespace mozilla {
 namespace dom {
 
 using indexedDB::IndexedDatabaseManager;
 
-  // Create as a file
-File::File(const nsAString& aName, const nsAString& aContentType,
-           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle)
-: nsDOMFileCC(aName, aContentType, aLength),
-  mFile(aFile), mFileHandle(aFileHandle),
-  mWholeFile(true), mStoredFile(false)
+// Create as a file
+FileImpl::FileImpl(const nsAString& aName, const nsAString& aContentType,
+                   uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle)
+  : DOMFileImplBase(aName, aContentType, aLength),
+    mFile(aFile), mFileHandle(aFileHandle), mWholeFile(true), mStoredFile(false)
 {
   MOZ_ASSERT(mFile, "Null file!");
   MOZ_ASSERT(mFileHandle, "Null file handle!");
 }
 
 // Create as a stored file
-File::File(const nsAString& aName, const nsAString& aContentType,
-           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
-           FileInfo* aFileInfo)
-: nsDOMFileCC(aName, aContentType, aLength),
-  mFile(aFile), mFileHandle(aFileHandle),
-  mWholeFile(true), mStoredFile(true)
+FileImpl::FileImpl(const nsAString& aName, const nsAString& aContentType,
+                   uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
+                   indexedDB::FileInfo* aFileInfo)
+  : DOMFileImplBase(aName, aContentType, aLength),
+    mFile(aFile), mFileHandle(aFileHandle), mWholeFile(true), mStoredFile(true)
 {
   MOZ_ASSERT(mFile, "Null file!");
   MOZ_ASSERT(mFileHandle, "Null file handle!");
   mFileInfos.AppendElement(aFileInfo);
 }
 
 // Create slice
-File::File(const File* aOther, uint64_t aStart, uint64_t aLength,
-           const nsAString& aContentType)
-: nsDOMFileCC(aContentType, aOther->mStart + aStart, aLength),
-  mFile(aOther->mFile), mFileHandle(aOther->mFileHandle),
-  mWholeFile(false), mStoredFile(aOther->mStoredFile)
+FileImpl::FileImpl(const FileImpl* aOther, uint64_t aStart, uint64_t aLength,
+                   const nsAString& aContentType)
+  : DOMFileImplBase(aContentType, aOther->mStart + aStart, aLength),
+    mFile(aOther->mFile), mFileHandle(aOther->mFileHandle),
+    mWholeFile(false), mStoredFile(aOther->mStoredFile)
 {
   MOZ_ASSERT(mFile, "Null file!");
   MOZ_ASSERT(mFileHandle, "Null file handle!");
 
   if (mStoredFile) {
-    FileInfo* fileInfo;
+    indexedDB::FileInfo* fileInfo;
 
     if (IndexedDatabaseManager::IsClosed()) {
       fileInfo = aOther->GetFileInfo();
     }
     else {
       MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
       fileInfo = aOther->GetFileInfo();
     }
 
     mFileInfos.AppendElement(fileInfo);
   }
 }
 
-File::~File()
+FileImpl::~FileImpl()
 {
 }
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(File, nsDOMFileCC,
-                                   mFileHandle)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(File)
-NS_INTERFACE_MAP_END_INHERITING(nsDOMFileCC)
+void
+FileImpl::Unlink()
+{
+  FileImpl* tmp = this;
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileHandle);
+}
 
-NS_IMPL_ADDREF_INHERITED(File, nsDOMFileCC)
-NS_IMPL_RELEASE_INHERITED(File, nsDOMFileCC)
+void
+FileImpl::Traverse(nsCycleCollectionTraversalCallback &cb)
+{
+  FileImpl* tmp = this;
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileHandle);
+}
 
-NS_IMETHODIMP
-File::GetInternalStream(nsIInputStream **aStream)
+nsresult
+FileImpl::GetInternalStream(nsIInputStream** aStream)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsresult rv = mFileHandle->OpenInputStream(mWholeFile, mStart, mLength,
                                              aStream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 already_AddRefed<nsIDOMBlob>
-File::CreateSlice(uint64_t aStart, uint64_t aLength,
-                  const nsAString& aContentType)
+FileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
+                      const nsAString& aContentType)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIDOMBlob> t =
-    new File(this, aStart, aLength, aContentType);
+    new DOMFileCC(new FileImpl(this, aStart, aLength, aContentType));
+
   return t.forget();
 }
 
-NS_IMETHODIMP
-File::GetMozFullPathInternal(nsAString &aFilename)
+nsresult
+FileImpl::GetMozFullPathInternal(nsAString& aFilename)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mIsFile, "Should only be called on files");
 
   return mFile->GetPath(aFilename);
 }
 
 } // namespace dom
--- a/dom/filehandle/File.h
+++ b/dom/filehandle/File.h
@@ -12,46 +12,46 @@
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsDOMFile.h"
 
 namespace mozilla {
 namespace dom {
 
 class FileHandle;
-
-class File : public nsDOMFileCC
-{
-public:
-  NS_DECL_ISUPPORTS_INHERITED
+class File;
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(File, nsDOMFileCC)
+class FileImpl : public DOMFileImplBase
+{
+  friend class File;
 
+public:
   // Create as a file
-  File(const nsAString& aName, const nsAString& aContentType,
-       uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle);
+  FileImpl(const nsAString& aName, const nsAString& aContentType,
+           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle);
 
   // Create as a stored file
-  File(const nsAString& aName, const nsAString& aContentType,
-       uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
-       FileInfo* aFileInfo);
+  FileImpl(const nsAString& aName, const nsAString& aContentType,
+           uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
+           indexedDB::FileInfo* aFileInfo);
 
   // Overrides
-  NS_IMETHOD
-  GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
+  virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
 
-  NS_IMETHOD
-  GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+  virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
+
+  virtual void Unlink() MOZ_OVERRIDE;
+  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
 protected:
   // Create slice
-  File(const File* aOther, uint64_t aStart, uint64_t aLength,
-       const nsAString& aContentType);
+  FileImpl(const FileImpl* aOther, uint64_t aStart, uint64_t aLength,
+           const nsAString& aContentType);
 
-  virtual ~File();
+  virtual ~FileImpl();
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength,
               const nsAString& aContentType) MOZ_OVERRIDE;
 
   virtual bool
   IsStoredFile() const MOZ_OVERRIDE
   {
--- a/dom/filehandle/MutableFile.cpp
+++ b/dom/filehandle/MutableFile.cpp
@@ -101,17 +101,17 @@ MutableFile::CreateStream(nsIFile* aFile
   return stream.forget();
 }
 
 // virtual
 already_AddRefed<nsIDOMFile>
 MutableFile::CreateFileObject(FileHandle* aFileHandle, uint32_t aFileSize)
 {
   nsCOMPtr<nsIDOMFile> file =
-    new File(mName, mType, aFileSize, mFile, aFileHandle);
+    new DOMFileCC(new FileImpl(mName, mType, aFileSize, mFile, aFileHandle));
 
   return file.forget();
 }
 
 // virtual
 JSObject*
 MutableFile::WrapObject(JSContext* aCx)
 {
--- a/dom/filesystem/CreateFileTask.cpp
+++ b/dom/filesystem/CreateFileTask.cpp
@@ -247,17 +247,17 @@ CreateFileTask::Work()
 
     mBlobStream->Close();
     mBlobStream = nullptr;
 
     if (mFileSystem->IsShutdown()) {
       return NS_ERROR_FAILURE;
     }
 
-    mTargetFile = new nsDOMFileFile(file);
+    mTargetFile = DOMFile::CreateFromFile(file);
     return NS_OK;
   }
 
   // Write file content from array data.
 
   uint32_t written;
   rv = bufferedOutputStream->Write(
     reinterpret_cast<char*>(mArrayData.Elements()),
@@ -266,17 +266,17 @@ CreateFileTask::Work()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mArrayData.Length() != written) {
     return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
   }
 
-  mTargetFile = new nsDOMFileFile(file);
+  mTargetFile = DOMFile::CreateFromFile(file);
   return NS_OK;
 }
 
 void
 CreateFileTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -175,17 +175,17 @@ GetFileOrDirectoryTask::Work()
     // Neither directory or file.
     return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
   }
 
   if (!mFileSystem->IsSafeFile(file)) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
-  mTargetFile = new nsDOMFileFile(file);
+  mTargetFile = DOMFile::CreateFromFile(file);
 
   return NS_OK;
 }
 
 void
 GetFileOrDirectoryTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -134,18 +134,18 @@ IDBMutableFile::UnsetThreadLocals()
 {
   QuotaManager::SetCurrentWindow(nullptr);
 }
 
 already_AddRefed<nsIDOMFile>
 IDBMutableFile::CreateFileObject(mozilla::dom::FileHandle* aFileHandle,
                                 uint32_t aFileSize)
 {
-  nsCOMPtr<nsIDOMFile> file =
-    new File(mName, mType, aFileSize, mFile, aFileHandle, mFileInfo);
+  nsCOMPtr<nsIDOMFile> file = new DOMFileCC(
+    new FileImpl(mName, mType, aFileSize, mFile, aFileHandle, mFileInfo));
 
   return file.forget();
 }
 
 // virtual
 JSObject*
 IDBMutableFile::WrapObject(JSContext* aCx)
 {
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -735,17 +735,18 @@ GetAddInfoCallback(JSContext* aCx, void*
 
 inline
 BlobChild*
 ActorFromRemoteBlob(nsIDOMBlob* aBlob)
 {
   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
+  nsRefPtr<DOMFile> blob = static_cast<DOMFile*>(aBlob);
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(blob->Impl());
   if (remoteBlob) {
     BlobChild* actor =
       static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
     NS_ASSERTION(actor, "Null actor?!");
     return actor;
   }
   return nullptr;
 }
@@ -831,18 +832,18 @@ public:
       nsCOMPtr<nsIDOMBlob> domBlob;
       if (aFile.mFile) {
         if (!ResolveMysteryBlob(aFile.mFile, aData.type, aData.size)) {
           return nullptr;
         }
         domBlob = aFile.mFile;
       }
       else {
-        domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile,
-                                    fileInfo);
+        domBlob = DOMFile::CreateFromFile(aData.type, aData.size, nativeFile,
+                                          fileInfo);
       }
 
       JS::Rooted<JS::Value> wrappedBlob(aCx);
       rv = nsContentUtils::WrapNative(aCx, domBlob, &NS_GET_IID(nsIDOMBlob),
                                       &wrappedBlob);
       if (NS_FAILED(rv)) {
         NS_WARNING("Failed to wrap native!");
         return nullptr;
@@ -856,18 +857,18 @@ public:
       if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size,
                               aData.lastModifiedDate)) {
         return nullptr;
       }
       domFile = do_QueryInterface(aFile.mFile);
       NS_ASSERTION(domFile, "This should never fail!");
     }
     else {
-      domFile = new nsDOMFileFile(aData.name, aData.type, aData.size,
-                                  nativeFile, fileInfo);
+      domFile = DOMFile::CreateFromFile(aData.name, aData.type, aData.size,
+                                        nativeFile, fileInfo);
     }
 
     JS::Rooted<JS::Value> wrappedFile(aCx);
     rv = nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile),
                                     &wrappedFile);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to wrap native!");
       return nullptr;
@@ -1785,17 +1786,18 @@ IDBObjectStore::ConvertBlobsToActors(
 
       nsCOMPtr<nsIFile> nativeFile =
         aFileManager->GetFileForId(directory, file.mFileInfo->Id());
       if (!nativeFile) {
         IDB_WARNING("Failed to get file!");
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
 
-      nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile, file.mFileInfo);
+      nsCOMPtr<nsIDOMBlob> blob = DOMFile::CreateFromFile(nativeFile,
+                                                          file.mFileInfo);
 
       BlobParent* actor =
         aContentParent->GetOrCreateActorForBlob(blob);
       if (!actor) {
         // This can only fail if the child has crashed.
         IDB_REPORT_INTERNAL_ERR();
         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
       }
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -75,30 +75,31 @@ NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRe
 
 // This class exists to keep a blob alive at least as long as its internal
 // stream.
 class BlobInputStreamTether : public nsIMultiplexInputStream,
                               public nsISeekableStream,
                               public nsIIPCSerializableInputStream
 {
   nsCOMPtr<nsIInputStream> mStream;
-  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<DOMFileImplBase> mSourceBlob;
 
   nsIMultiplexInputStream* mWeakMultiplexStream;
   nsISeekableStream* mWeakSeekableStream;
   nsIIPCSerializableInputStream* mWeakSerializableStream;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_FORWARD_NSIINPUTSTREAM(mStream->)
   NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream)
   NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream)
   NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream)
 
-  BlobInputStreamTether(nsIInputStream* aStream, nsIDOMBlob* aSourceBlob)
+  BlobInputStreamTether(nsIInputStream* aStream,
+                        mozilla::dom::DOMFileImplBase* aSourceBlob)
   : mStream(aStream), mSourceBlob(aSourceBlob), mWeakMultiplexStream(nullptr),
     mWeakSeekableStream(nullptr), mWeakSerializableStream(nullptr)
   {
     MOZ_ASSERT(aStream);
     MOZ_ASSERT(aSourceBlob);
 
     nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
       do_QueryInterface(aStream);
@@ -149,24 +150,25 @@ NS_INTERFACE_MAP_END
 
 class RemoteInputStream : public nsIInputStream,
                           public nsISeekableStream,
                           public nsIIPCSerializableInputStream,
                           public IPrivateRemoteInputStream
 {
   mozilla::Monitor mMonitor;
   nsCOMPtr<nsIInputStream> mStream;
-  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<mozilla::dom::DOMFileImplBase> mSourceBlob;
   nsISeekableStream* mWeakSeekableStream;
   ActorType mOrigin;
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
-  RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorType aOrigin)
+  RemoteInputStream(mozilla::dom::DOMFileImplBase* aSourceBlob,
+                    ActorType aOrigin)
   : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
     mWeakSeekableStream(nullptr), mOrigin(aOrigin)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aSourceBlob);
   }
 
   void
@@ -220,17 +222,17 @@ public:
   }
 
   NS_IMETHOD
   Close() MOZ_OVERRIDE
   {
     nsresult rv = BlockAndWaitForStream();
     NS_ENSURE_SUCCESS(rv, rv);
 
-    nsCOMPtr<nsIDOMBlob> sourceBlob;
+    nsRefPtr<mozilla::dom::DOMFileImplBase> sourceBlob;
     mSourceBlob.swap(sourceBlob);
 
     rv = mStream->Close();
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
@@ -481,23 +483,20 @@ protected:
 
 private:
   // This method is only called by the IPDL message machinery.
   virtual bool
   Recv__delete__(const InputStreamParams& aParams,
                  const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE;
 };
 
-nsDOMFileBase*
+DOMFile*
 ToConcreteBlob(nsIDOMBlob* aBlob)
 {
-  // XXX This is only safe so long as all blob implementations in our tree
-  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
-  //     a real interface or something.
-  return static_cast<nsDOMFileBase*>(aBlob);
+  return static_cast<DOMFile*>(aBlob);
 }
 
 } // anonymous namespace
 
 // Each instance of this class will be dispatched to the network stream thread
 // pool to run the first time where it will open the file input stream. It will
 // then dispatch itself back to the main thread to send the child process its
 // response (assuming that the child has not crashed). The runnable will then
@@ -698,45 +697,44 @@ private:
     return NS_OK;
   }
 };
 
 /*******************************************************************************
  * BlobChild::RemoteBlob Declaration
  ******************************************************************************/
 
-class BlobChild::RemoteBlob MOZ_FINAL
-  : public nsDOMFile
-  , public nsIRemoteBlob
+class BlobChild::RemoteBlob MOZ_FINAL : public DOMFileImplBase
+                                      , public nsIRemoteBlob
 {
   class StreamHelper;
   class SliceHelper;
 
   BlobChild* mActor;
 
 public:
   RemoteBlob(const nsAString& aName,
              const nsAString& aContentType,
              uint64_t aLength,
              uint64_t aModDate)
-    : nsDOMFile(aName, aContentType, aLength, aModDate)
+    : DOMFileImplBase(aName, aContentType, aLength, aModDate)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   RemoteBlob(const nsAString& aContentType, uint64_t aLength)
-    : nsDOMFile(aContentType, aLength)
+    : DOMFileImplBase(aContentType, aLength)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   RemoteBlob()
-    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   void
   SetActor(BlobChild* aActor)
   {
@@ -745,20 +743,20 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
               MOZ_OVERRIDE;
 
-  NS_IMETHOD
+  virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  NS_IMETHOD
+  virtual nsresult
   GetLastModifiedDate(JSContext* cx,
                       JS::MutableHandle<JS::Value> aLastModifiedDate)
                       MOZ_OVERRIDE;
 
   virtual void*
   GetPBlob() MOZ_OVERRIDE;
 
 private:
@@ -770,22 +768,22 @@ private:
   }
 };
 
 class BlobChild::RemoteBlob::StreamHelper MOZ_FINAL
   : public nsRunnable
 {
   mozilla::Monitor mMonitor;
   BlobChild* mActor;
-  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<mozilla::dom::DOMFileImplBase> mSourceBlob;
   nsRefPtr<RemoteInputStream> mInputStream;
   bool mDone;
 
 public:
-  StreamHelper(BlobChild* aActor, nsIDOMBlob* aSourceBlob)
+  StreamHelper(BlobChild* aActor, mozilla::dom::DOMFileImplBase* aSourceBlob)
     : mMonitor("BlobChild::RemoteBlob::StreamHelper::mMonitor")
     , mActor(aActor)
     , mSourceBlob(aSourceBlob)
     , mDone(false)
   {
     // This may be created on any thread.
     MOZ_ASSERT(aActor);
     MOZ_ASSERT(aSourceBlob);
@@ -990,17 +988,17 @@ private:
     }
   }
 };
 
 /*******************************************************************************
  * BlobChild::RemoteBlob Implementation
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob)
+NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, DOMFileImplBase, nsIRemoteBlob)
 
 already_AddRefed<nsIDOMBlob>
 BlobChild::
 RemoteBlob::CreateSlice(uint64_t aStart,
                         uint64_t aLength,
                         const nsAString& aContentType)
 {
   if (!mActor) {
@@ -1012,29 +1010,29 @@ RemoteBlob::CreateSlice(uint64_t aStart,
   nsCOMPtr<nsIDOMBlob> slice;
   nsresult rv =
     helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return slice.forget();
 }
 
-NS_IMETHODIMP
+nsresult
 BlobChild::
 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
 {
   if (!mActor) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
   return helper->GetStream(aStream);
 }
 
-NS_IMETHODIMP
+nsresult
 BlobChild::
 RemoteBlob::GetLastModifiedDate(JSContext* cx,
                                 JS::MutableHandle<JS::Value> aLastModifiedDate)
 {
   if (IsDateUnknown()) {
     aLastModifiedDate.setNull();
   } else {
     JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
@@ -1090,19 +1088,21 @@ BlobChild::BlobChild(nsIContentChild* aM
   mBlobIsFile =
     paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
     paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
 
   nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
   MOZ_ASSERT(remoteBlob);
 
   remoteBlob->SetActor(this);
-  remoteBlob.forget(&mRemoteBlob);
 
-  mBlob = mRemoteBlob;
+  nsRefPtr<DOMFile> blob = new DOMFile(remoteBlob);
+  blob.forget(&mBlob);
+
+  mRemoteBlob = remoteBlob;
   mOwnsBlob = true;
 }
 
 BlobChild::~BlobChild()
 {
 }
 
 BlobChild*
@@ -1352,17 +1352,17 @@ BlobChild::RecvResolveMystery(const Reso
   MOZ_ASSERT(!mRemoteBlob);
   MOZ_ASSERT(mOwnsBlob);
 
   if (!mBlobIsFile) {
     MOZ_ASSERT(false, "Must always be a file!");
     return false;
   }
 
-  nsDOMFileBase* blob = ToConcreteBlob(mBlob);
+  DOMFile* blob = ToConcreteBlob(mBlob);
 
   switch (aParams.type()) {
     case ResolveMysteryParams::TNormalBlobConstructorParams: {
       const NormalBlobConstructorParams& params =
         aParams.get_NormalBlobConstructorParams();
       nsString voidString;
       voidString.SetIsVoid(true);
       blob->SetLazyData(voidString, params.contentType(), params.length(),
@@ -1384,46 +1384,45 @@ BlobChild::RecvResolveMystery(const Reso
 
   return true;
 }
 
 /*******************************************************************************
  * BlobParent::RemoteBlob Declaration
  ******************************************************************************/
 
-class BlobParent::RemoteBlob MOZ_FINAL
-  : public nsDOMFile
-  , public nsIRemoteBlob
+class BlobParent::RemoteBlob MOZ_FINAL : public mozilla::dom::DOMFileImplBase
+                                       , public nsIRemoteBlob
 {
   class StreamHelper;
   class SliceHelper;
 
   BlobParent* mActor;
   InputStreamParams mInputStreamParams;
 
 public:
   RemoteBlob(const nsAString& aName,
              const nsAString& aContentType,
              uint64_t aLength,
              uint64_t aModDate)
-    : nsDOMFile(aName, aContentType, aLength, aModDate)
+    : DOMFileImplBase(aName, aContentType, aLength, aModDate)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   RemoteBlob(const nsAString& aContentType, uint64_t aLength)
-    : nsDOMFile(aContentType, aLength)
+    : DOMFileImplBase(aContentType, aLength)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   RemoteBlob()
-    : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
+    : DOMFileImplBase(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
     , mActor(nullptr)
   {
     mImmutable = true;
   }
 
   void
   SetActor(BlobParent* aActor)
   {
@@ -1442,47 +1441,47 @@ public:
   }
 
   NS_DECL_ISUPPORTS_INHERITED
 
   virtual already_AddRefed<nsIDOMBlob>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
               MOZ_OVERRIDE;
 
-  NS_IMETHOD
+  virtual nsresult
   GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
-  NS_IMETHOD
+  virtual nsresult
   GetLastModifiedDate(JSContext* cx,
                       JS::MutableHandle<JS::Value> aLastModifiedDate)
                       MOZ_OVERRIDE;
 
-  virtual void*
+  void*
   GetPBlob() MOZ_OVERRIDE;
 
 private:
   ~RemoteBlob()
   {
     if (mActor) {
       mActor->NoteDyingRemoteBlob();
     }
   }
 };
 
 class BlobParent::RemoteBlob::StreamHelper MOZ_FINAL
   : public nsRunnable
 {
   mozilla::Monitor mMonitor;
   BlobParent* mActor;
-  nsCOMPtr<nsIDOMBlob> mSourceBlob;
+  nsRefPtr<mozilla::dom::DOMFileImplBase> mSourceBlob;
   nsRefPtr<RemoteInputStream> mInputStream;
   bool mDone;
 
 public:
-  StreamHelper(BlobParent* aActor, nsIDOMBlob* aSourceBlob)
+  StreamHelper(BlobParent* aActor, mozilla::dom::DOMFileImplBase* aSourceBlob)
     : mMonitor("BlobParent::RemoteBlob::StreamHelper::mMonitor")
     , mActor(aActor)
     , mSourceBlob(aSourceBlob)
     , mDone(false)
   {
     // This may be created on any thread.
     MOZ_ASSERT(aActor);
     MOZ_ASSERT(aSourceBlob);
@@ -1689,17 +1688,18 @@ private:
     }
   }
 };
 
 /*******************************************************************************
  * BlobChild::RemoteBlob Implementation
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob)
+NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, DOMFileImplBase,
+                            nsIRemoteBlob)
 
 already_AddRefed<nsIDOMBlob>
 BlobParent::
 RemoteBlob::CreateSlice(uint64_t aStart,
                         uint64_t aLength,
                         const nsAString& aContentType)
 {
   if (!mActor) {
@@ -1711,17 +1711,17 @@ RemoteBlob::CreateSlice(uint64_t aStart,
   nsCOMPtr<nsIDOMBlob> slice;
   nsresult rv =
     helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return slice.forget();
 }
 
-NS_IMETHODIMP
+nsresult
 BlobParent::
 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
 {
   if (mInputStreamParams.type() != InputStreamParams::T__None) {
     nsTArray<FileDescriptor> fds;
     nsCOMPtr<nsIInputStream> realStream =
       DeserializeInputStream(mInputStreamParams, fds);
     if (!realStream) {
@@ -1738,17 +1738,17 @@ RemoteBlob::GetInternalStream(nsIInputSt
   if (!mActor) {
     return NS_ERROR_UNEXPECTED;
   }
 
   nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
   return helper->GetStream(aStream);
 }
 
-NS_IMETHODIMP
+nsresult
 BlobParent::
 RemoteBlob::GetLastModifiedDate(JSContext* cx,
                                 JS::MutableHandle<JS::Value> aLastModifiedDate)
 {
   if (IsDateUnknown()) {
     aLastModifiedDate.setNull();
   } else {
     JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate);
@@ -1805,19 +1805,21 @@ BlobParent::BlobParent(nsIContentParent*
     paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
     paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
 
   nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
   MOZ_ASSERT(remoteBlob);
 
   remoteBlob->SetActor(this);
   remoteBlob->MaybeSetInputStream(aParams);
-  remoteBlob.forget(&mRemoteBlob);
 
-  mBlob = mRemoteBlob;
+  nsRefPtr<DOMFile> blob = new DOMFile(remoteBlob);
+  blob.forget(&mBlob);
+
+  mRemoteBlob = remoteBlob;
   mOwnsBlob = true;
 }
 
 BlobParent::~BlobParent()
 {
 }
 
 BlobParent*
@@ -2056,17 +2058,18 @@ BlobParent::RecvPBlobStreamConstructor(P
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(!mRemoteBlob);
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, false);
 
-  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
+  nsRefPtr<DOMFile> blob = static_cast<DOMFile*>(mBlob);
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(blob->Impl());
 
   nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
   if (remoteBlob) {
     remoteStream = do_QueryInterface(stream);
   }
 
   // There are three cases in which we can use the stream obtained from the blob
   // directly as our serialized stream:
@@ -2121,17 +2124,17 @@ BlobParent::RecvResolveMystery(const Res
   MOZ_ASSERT(!mRemoteBlob);
   MOZ_ASSERT(mOwnsBlob);
 
   if (!mBlobIsFile) {
     MOZ_ASSERT(false, "Must always be a file!");
     return false;
   }
 
-  nsDOMFileBase* blob = ToConcreteBlob(mBlob);
+  DOMFile* blob = ToConcreteBlob(mBlob);
 
   switch (aParams.type()) {
     case ResolveMysteryParams::TNormalBlobConstructorParams: {
       const NormalBlobConstructorParams& params =
         aParams.get_NormalBlobConstructorParams();
       nsString voidString;
       voidString.SetIsVoid(true);
       blob->SetLazyData(voidString, params.contentType(),
--- a/dom/ipc/FilePickerParent.cpp
+++ b/dom/ipc/FilePickerParent.cpp
@@ -144,25 +144,25 @@ FilePickerParent::Done(int16_t aResult)
     NS_ENSURE_SUCCESS_VOID(mFilePicker->GetFiles(getter_AddRefs(iter)));
 
     nsCOMPtr<nsISupports> supports;
     bool loop = true;
     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
       iter->GetNext(getter_AddRefs(supports));
       if (supports) {
         nsCOMPtr<nsIFile> file = do_QueryInterface(supports);
-        nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
+        nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
         domfiles.AppendElement(domfile);
       }
     }
   } else {
     nsCOMPtr<nsIFile> file;
     mFilePicker->GetFile(getter_AddRefs(file));
     if (file) {
-      nsCOMPtr<nsIDOMFile> domfile = new nsDOMFileFile(file);
+      nsCOMPtr<nsIDOMFile> domfile = DOMFile::CreateFromFile(file);
       domfiles.AppendElement(domfile);
     }
   }
 
   MOZ_ASSERT(!mRunnable);
   mRunnable = new FileSizeAndDateRunnable(this, domfiles);
   if (!mRunnable->Dispatch()) {
     unused << Send__delete__(this, void_t(), nsIFilePicker::returnCancel);
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -97,17 +97,19 @@ nsIContentChild::DeallocPBlobChild(PBlob
 BlobChild*
 nsIContentChild::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   // If the blob represents a remote blob then we can simply pass its actor back
   // here.
-  if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
+  const auto* domFile = static_cast<DOMFile*>(aBlob);
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(domFile->Impl());
+  if (remoteBlob) {
     BlobChild* actor =
       static_cast<BlobChild*>(
         static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
     MOZ_ASSERT(actor);
     if (actor->Manager() == this) {
       return actor;
     }
   }
@@ -117,19 +119,19 @@ nsIContentChild::GetOrCreateActorForBlob
   if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
     NS_WARNING("Failed to make blob immutable!");
     return nullptr;
   }
 
 #ifdef DEBUG
   {
     // XXX This is only safe so long as all blob implementations in our tree
-    //     inherit nsDOMFileBase. If that ever changes then this will need to
+    //     inherit DOMFileImplBase. If that ever changes then this will need to
     //     grow a real interface or something.
-    const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
+    const auto* blob = static_cast<DOMFileImplBase*>(domFile->Impl());
 
     MOZ_ASSERT(!blob->IsSizeUnknown());
     MOZ_ASSERT(!blob->IsDateUnknown());
   }
 #endif
 
   ParentBlobConstructorParams params;
 
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -153,17 +153,19 @@ nsIContentParent::DeallocPBlobParent(PBl
 BlobParent*
 nsIContentParent::GetOrCreateActorForBlob(nsIDOMBlob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   // If the blob represents a remote blob for this ContentParent then we can
   // simply pass its actor back here.
-  if (nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob)) {
+  const auto* domFile = static_cast<DOMFile*>(aBlob);
+  nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(domFile->Impl());
+  if (remoteBlob) {
     if (BlobParent* actor = static_cast<BlobParent*>(
           static_cast<PBlobParent*>(remoteBlob->GetPBlob()))) {
       MOZ_ASSERT(actor);
 
       if (actor->Manager() == this) {
         return actor;
       }
     }
@@ -172,19 +174,19 @@ nsIContentParent::GetOrCreateActorForBlo
   // All blobs shared between processes must be immutable.
   nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(aBlob);
   if (!mutableBlob || NS_FAILED(mutableBlob->SetMutable(false))) {
     NS_WARNING("Failed to make blob immutable!");
     return nullptr;
   }
 
   // XXX This is only safe so long as all blob implementations in our tree
-  //     inherit nsDOMFileBase. If that ever changes then this will need to grow
+  //     inherit DOMFileImplBase. If that ever changes then this will need to grow
   //     a real interface or something.
-  const auto* blob = static_cast<nsDOMFileBase*>(aBlob);
+  const auto* blob = static_cast<DOMFileImplBase*>(domFile->Impl());
 
   ChildBlobConstructorParams params;
 
   if (blob->IsSizeUnknown() || blob->IsDateUnknown()) {
     // We don't want to call GetSize or GetLastModifiedDate
     // yet since that may stat a file on the main thread
     // here. Instead we'll learn the size lazily from the
     // other process.
--- a/dom/mobilemessage/src/DOMMobileMessageError.cpp
+++ b/dom/mobilemessage/src/DOMMobileMessageError.cpp
@@ -56,16 +56,16 @@ DOMMobileMessageError::GetData(OwningMoz
     return;
   }
 
   if (mMms) {
     aRetVal.SetAsMozMmsMessage() = mMms;
     return;
   }
 
-  MOZ_ASSUME_UNREACHABLE("Bad object with invalid mSms and mMms.");
+  MOZ_CRASH("Bad object with invalid mSms and mMms.");
 }
 
 JSObject*
 DOMMobileMessageError::WrapObject(JSContext* aCx)
 {
   return DOMMobileMessageErrorBinding::Wrap(aCx, this);
 }
--- a/dom/mobilemessage/src/MmsMessage.cpp
+++ b/dom/mobilemessage/src/MmsMessage.cpp
@@ -377,17 +377,17 @@ MmsMessage::GetData(ContentParent* aPare
     const Attachment &element = mAttachments[i];
     mma.id().Assign(element.id);
     mma.location().Assign(element.location);
 
     // This is a workaround. Sometimes the blob we get from the database
     // doesn't have a valid last modified date, making the ContentParent
     // send a "Mystery Blob" to the ContentChild. Attempting to get the
     // last modified date of blob can force that value to be initialized.
-    nsDOMFileBase* file = static_cast<nsDOMFileBase*>(element.content.get());
+    DOMFile* file = static_cast<DOMFile*>(element.content.get());
     if (file->IsDateUnknown()) {
       uint64_t date;
       if (NS_FAILED(file->GetMozLastModifiedDate(&date))) {
         NS_WARNING("Failed to get last modified date!");
       }
     }
 
     mma.contentParent() = aParent->GetOrCreateActorForBlob(element.content);
--- a/dom/plugins/base/nsPluginNativeWindowGtk.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowGtk.cpp
@@ -336,10 +336,14 @@ socket_unrealize_cb(GtkWidget *widget, g
       XUnmapWindow(display, child);
       XReparentWindow(display, child, DefaultRootWindow(display), 0, 0);
     }
   }
 
   if (children) XFree(children);
 
   mozilla::FinishX(display);
+#if (MOZ_WIDGET_GTK == 3)
+  gdk_error_trap_pop_ignored();
+#else
   gdk_error_trap_pop();
+#endif
 }
--- a/dom/telephony/TelephonyCallId.cpp
+++ b/dom/telephony/TelephonyCallId.cpp
@@ -40,17 +40,17 @@ TelephonyCallId::GetPresentationStr(uint
       return CallIdPresentation::Allowed;
     case nsITelephonyService::CALL_PRESENTATION_RESTRICTED:
       return CallIdPresentation::Restricted;
     case nsITelephonyService::CALL_PRESENTATION_UNKNOWN:
       return CallIdPresentation::Unknown;
     case nsITelephonyService::CALL_PRESENTATION_PAYPHONE:
       return CallIdPresentation::Payphone;
     default:
-      MOZ_ASSUME_UNREACHABLE("Bad presentation!");
+      MOZ_CRASH("Bad presentation!");
   }
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TelephonyCallId, mWindow)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TelephonyCallId)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TelephonyCallId)
 
--- a/dom/wifi/WifiHotspotUtils.h
+++ b/dom/wifi/WifiHotspotUtils.h
@@ -33,12 +33,12 @@ private:
 
 // Defines a function type with the right arguments and return type.
 #define DEFINE_DLFUNC(name, ret, args...) typedef ret (*FUNC##name)(args);
 
 // Set up a dlsymed function ready to use.
 #define USE_DLFUNC(name)                                                      \
   FUNC##name name = (FUNC##name) dlsym(GetSharedLibrary(), #name);            \
   if (!name) {                                                                \
-    MOZ_ASSUME_UNREACHABLE("Symbol not found in shared library : " #name);    \
+    MOZ_CRASH("Symbol not found in shared library : " #name);                 \
   }
 
 #endif // WifiHotspotUtils_h
--- a/dom/workers/File.cpp
+++ b/dom/workers/File.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "File.h"
 
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsDOMBlobBuilder.h"
 #include "nsError.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsCOMPtr.h"
 #include "nsJSUtils.h"
 #include "nsString.h"
@@ -80,18 +80,20 @@ private:
     return GetPrivate(aObj);
   }
 
   static bool
   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
 
-    nsRefPtr<nsDOMMultipartFile> file = new nsDOMMultipartFile();
-    nsresult rv = file->InitBlob(aCx, args.length(), args.array(), Unwrap);
+    nsRefPtr<DOMMultipartFileImpl> fileImpl = new DOMMultipartFileImpl();
+    nsRefPtr<mozilla::dom::DOMFile> file = new mozilla::dom::DOMFile(fileImpl);
+
+    nsresult rv = fileImpl->InitBlob(aCx, args.length(), args.array(), Unwrap);
     if (NS_FAILED(rv)) {
       return Throw(aCx, rv);
     }
 
     JSObject* obj = file::CreateBlob(aCx, file);
     if (!obj) {
       return false;
     }
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -46,16 +46,17 @@
 #include "nsXBLBinding.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "mozilla/dom/XBLChildrenElement.h"
 
 #include "prprf.h"
 #include "nsNodeUtils.h"
 #include "nsJSUtils.h"
+#include "nsCycleCollector.h"
 
 // Nasty hack.  Maybe we could move some of the classinfo utility methods
 // (e.g. WrapNative) over to nsContentUtils?
 #include "nsDOMClassInfo.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/ShadowRoot.h"
 
@@ -68,17 +69,17 @@ using namespace mozilla::dom;
 //
 // The JS class for XBLBinding
 //
 static void
 XBLFinalize(JSFreeOp *fop, JSObject *obj)
 {
   nsXBLDocumentInfo* docInfo =
     static_cast<nsXBLDocumentInfo*>(::JS_GetPrivate(obj));
-  nsContentUtils::DeferredFinalize(docInfo);
+  cyclecollector::DeferredFinalize(docInfo);
 }
 
 static bool
 XBLEnumerate(JSContext *cx, JS::Handle<JSObject*> obj)
 {
   nsXBLPrototypeBinding* protoBinding =
     static_cast<nsXBLPrototypeBinding*>(::JS_GetReservedSlot(obj, 0).toPrivate());
   MOZ_ASSERT(protoBinding);
rename from editor/composer/src/crashtests/351236-1.html
rename to editor/composer/crashtests/351236-1.html
rename from editor/composer/src/crashtests/407062-1.html
rename to editor/composer/crashtests/407062-1.html
rename from editor/composer/src/crashtests/419563-1.xhtml
rename to editor/composer/crashtests/419563-1.xhtml
rename from editor/composer/src/crashtests/428844-1-inner.xhtml
rename to editor/composer/crashtests/428844-1-inner.xhtml
rename from editor/composer/src/crashtests/428844-1.html
rename to editor/composer/crashtests/428844-1.html
rename from editor/composer/src/crashtests/461049-1.html
rename to editor/composer/crashtests/461049-1.html
rename from editor/composer/src/crashtests/crashtests.list
rename to editor/composer/crashtests/crashtests.list
rename from editor/composer/src/crashtests/removing-editable-xslt-inner.xhtml
rename to editor/composer/crashtests/removing-editable-xslt-inner.xhtml
rename from editor/composer/src/crashtests/removing-editable-xslt.html
rename to editor/composer/crashtests/removing-editable-xslt.html
--- a/editor/composer/moz.build
+++ b/editor/composer/moz.build
@@ -1,8 +1,65 @@
 # -*- Mode: python; c-basic-offset: 4; 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/.
 
-PARALLEL_DIRS += ['public', 'src']
 TEST_DIRS += ['test']
+
+XPIDL_SOURCES += [
+    'nsIEditingSession.idl',
+]
+
+XPIDL_MODULE = 'composer'
+
+UNIFIED_SOURCES += [
+    'nsComposerCommands.cpp',
+    'nsComposerCommandsUpdater.cpp',
+    'nsComposerController.cpp',
+    'nsComposerDocumentCommands.cpp',
+    'nsComposerRegistration.cpp',
+    'nsComposeTxtSrvFilter.cpp',
+    'nsEditingSession.cpp',
+    'nsEditorSpellCheck.cpp',
+]
+
+FAIL_ON_WARNINGS = True
+
+FINAL_LIBRARY = 'xul'
+RESOURCE_FILES += [
+    'res/EditorOverride.css',
+    'res/grabber.gif',
+    'res/table-add-column-after-active.gif',
+    'res/table-add-column-after-hover.gif',
+    'res/table-add-column-after.gif',
+    'res/table-add-column-before-active.gif',
+    'res/table-add-column-before-hover.gif',
+    'res/table-add-column-before.gif',
+    'res/table-add-row-after-active.gif',
+    'res/table-add-row-after-hover.gif',
+    'res/table-add-row-after.gif',
+    'res/table-add-row-before-active.gif',
+    'res/table-add-row-before-hover.gif',
+    'res/table-add-row-before.gif',
+    'res/table-remove-column-active.gif',
+    'res/table-remove-column-hover.gif',
+    'res/table-remove-column.gif',
+    'res/table-remove-row-active.gif',
+    'res/table-remove-row-hover.gif',
+    'res/table-remove-row.gif',
+    'res/text_caret.png',
+    'res/text_caret@1.5x.png',
+    'res/text_caret@2.25x.png',
+    'res/text_caret@2x.png',
+    'res/text_caret_tilt_left.png',
+    'res/text_caret_tilt_left@1.5x.png',
+    'res/text_caret_tilt_left@2.25x.png',
+    'res/text_caret_tilt_left@2x.png',
+    'res/text_caret_tilt_right.png',
+    'res/text_caret_tilt_right@1.5x.png',
+    'res/text_caret_tilt_right@2.25x.png',
+    'res/text_caret_tilt_right@2x.png',
+    'res/text_selection_handle.png',
+    'res/text_selection_handle@1.5.png',
+    'res/text_selection_handle@2.png',
+]
rename from editor/composer/src/nsComposeTxtSrvFilter.cpp
rename to editor/composer/nsComposeTxtSrvFilter.cpp
rename from editor/composer/src/nsComposeTxtSrvFilter.h
rename to editor/composer/nsComposeTxtSrvFilter.h
rename from editor/composer/src/nsComposerCommands.cpp
rename to editor/composer/nsComposerCommands.cpp
rename from editor/composer/src/nsComposerCommands.h
rename to editor/composer/nsComposerCommands.h
rename from editor/composer/src/nsComposerCommandsUpdater.cpp
rename to editor/composer/nsComposerCommandsUpdater.cpp
rename from editor/composer/src/nsComposerCommandsUpdater.h
rename to editor/composer/nsComposerCommandsUpdater.h
rename from editor/composer/src/nsComposerController.cpp
rename to editor/composer/nsComposerController.cpp
rename from editor/composer/src/nsComposerController.h
rename to editor/composer/nsComposerController.h
rename from editor/composer/src/nsComposerDocumentCommands.cpp
rename to editor/composer/nsComposerDocumentCommands.cpp
rename from editor/composer/src/nsComposerRegistration.cpp
rename to editor/composer/nsComposerRegistration.cpp
rename from editor/composer/src/nsEditingSession.cpp
rename to editor/composer/nsEditingSession.cpp
rename from editor/composer/src/nsEditingSession.h
rename to editor/composer/nsEditingSession.h
rename from editor/composer/src/nsEditorSpellCheck.cpp
rename to editor/composer/nsEditorSpellCheck.cpp
rename from editor/composer/src/nsEditorSpellCheck.h
rename to editor/composer/nsEditorSpellCheck.h
rename from editor/composer/public/nsIEditingSession.idl
rename to editor/composer/nsIEditingSession.idl
deleted file mode 100644
--- a/editor/composer/public/moz.build
+++ /dev/null
@@ -1,12 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-XPIDL_SOURCES += [
-    'nsIEditingSession.idl',
-]
-
-XPIDL_MODULE = 'composer'
-
rename from editor/composer/src/res/EditorOverride.css
rename to editor/composer/res/EditorOverride.css
rename from editor/composer/src/res/grabber.gif
rename to editor/composer/res/grabber.gif
rename from editor/composer/src/res/table-add-column-after-active.gif
rename to editor/composer/res/table-add-column-after-active.gif
rename from editor/composer/src/res/table-add-column-after-hover.gif
rename to editor/composer/res/table-add-column-after-hover.gif
rename from editor/composer/src/res/table-add-column-after.gif
rename to editor/composer/res/table-add-column-after.gif
rename from editor/composer/src/res/table-add-column-before-active.gif
rename to editor/composer/res/table-add-column-before-active.gif
rename from editor/composer/src/res/table-add-column-before-hover.gif
rename to editor/composer/res/table-add-column-before-hover.gif
rename from editor/composer/src/res/table-add-column-before.gif
rename to editor/composer/res/table-add-column-before.gif
rename from editor/composer/src/res/table-add-row-after-active.gif
rename to editor/composer/res/table-add-row-after-active.gif
rename from editor/composer/src/res/table-add-row-after-hover.gif
rename to editor/composer/res/table-add-row-after-hover.gif
rename from editor/composer/src/res/table-add-row-after.gif
rename to editor/composer/res/table-add-row-after.gif
rename from editor/composer/src/res/table-add-row-before-active.gif
rename to editor/composer/res/table-add-row-before-active.gif
rename from editor/composer/src/res/table-add-row-before-hover.gif
rename to editor/composer/res/table-add-row-before-hover.gif
rename from editor/composer/src/res/table-add-row-before.gif
rename to editor/composer/res/table-add-row-before.gif
rename from editor/composer/src/res/table-remove-column-active.gif
rename to editor/composer/res/table-remove-column-active.gif
rename from editor/composer/src/res/table-remove-column-hover.gif
rename to editor/composer/res/table-remove-column-hover.gif
rename from editor/composer/src/res/table-remove-column.gif
rename to editor/composer/res/table-remove-column.gif
rename from editor/composer/src/res/table-remove-row-active.gif
rename to editor/composer/res/table-remove-row-active.gif
rename from editor/composer/src/res/table-remove-row-hover.gif
rename to editor/composer/res/table-remove-row-hover.gif
rename from editor/composer/src/res/table-remove-row.gif
rename to editor/composer/res/table-remove-row.gif
rename from editor/composer/src/res/text_caret.png
rename to editor/composer/res/text_caret.png
rename from editor/composer/src/res/text_caret@1.5x.png
rename to editor/composer/res/text_caret@1.5x.png
rename from editor/composer/src/res/text_caret@2.25x.png
rename to editor/composer/res/text_caret@2.25x.png
rename from editor/composer/src/res/text_caret@2x.png
rename to editor/composer/res/text_caret@2x.png
rename from editor/composer/src/res/text_caret_tilt_left.png
rename to editor/composer/res/text_caret_tilt_left.png
rename from editor/composer/src/res/text_caret_tilt_left@1.5x.png
rename to editor/composer/res/text_caret_tilt_left@1.5x.png
rename from editor/composer/src/res/text_caret_tilt_left@2.25x.png
rename to editor/composer/res/text_caret_tilt_left@2.25x.png
rename from editor/composer/src/res/text_caret_tilt_left@2x.png
rename to editor/composer/res/text_caret_tilt_left@2x.png
rename from editor/composer/src/res/text_caret_tilt_right.png
rename to editor/composer/res/text_caret_tilt_right.png
rename from editor/composer/src/res/text_caret_tilt_right@1.5x.png
rename to editor/composer/res/text_caret_tilt_right@1.5x.png
rename from editor/composer/src/res/text_caret_tilt_right@2.25x.png
rename to editor/composer/res/text_caret_tilt_right@2.25x.png
rename from editor/composer/src/res/text_caret_tilt_right@2x.png
rename to editor/composer/res/text_caret_tilt_right@2x.png
rename from editor/composer/src/res/text_selection_handle.png
rename to editor/composer/res/text_selection_handle.png
rename from editor/composer/src/res/text_selection_handle@1.5.png
rename to editor/composer/res/text_selection_handle@1.5.png
rename from editor/composer/src/res/text_selection_handle@2.png
rename to editor/composer/res/text_selection_handle@2.png
deleted file mode 100644
--- a/editor/composer/src/moz.build
+++ /dev/null
@@ -1,57 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-UNIFIED_SOURCES += [
-    'nsComposerCommands.cpp',
-    'nsComposerCommandsUpdater.cpp',
-    'nsComposerController.cpp',
-    'nsComposerDocumentCommands.cpp',
-    'nsComposerRegistration.cpp',
-    'nsComposeTxtSrvFilter.cpp',
-    'nsEditingSession.cpp',
-    'nsEditorSpellCheck.cpp',
-]
-
-FAIL_ON_WARNINGS = True
-
-FINAL_LIBRARY = 'xul'
-RESOURCE_FILES += [
-    'res/EditorOverride.css',
-    'res/grabber.gif',
-    'res/table-add-column-after-active.gif',
-    'res/table-add-column-after-hover.gif',
-    'res/table-add-column-after.gif',
-    'res/table-add-column-before-active.gif',
-    'res/table-add-column-before-hover.gif',
-    'res/table-add-column-before.gif',
-    'res/table-add-row-after-active.gif',
-    'res/table-add-row-after-hover.gif',
-    'res/table-add-row-after.gif',
-    'res/table-add-row-before-active.gif',
-    'res/table-add-row-before-hover.gif',
-    'res/table-add-row-before.gif',
-    'res/table-remove-column-active.gif',
-    'res/table-remove-column-hover.gif',
-    'res/table-remove-column.gif',
-    'res/table-remove-row-active.gif',
-    'res/table-remove-row-hover.gif',
-    'res/table-remove-row.gif',
-    'res/text_caret.png',
-    'res/text_caret@1.5x.png',
-    'res/text_caret@2.25x.png',
-    'res/text_caret@2x.png',
-    'res/text_caret_tilt_left.png',
-    'res/text_caret_tilt_left@1.5x.png',
-    'res/text_caret_tilt_left@2.25x.png',
-    'res/text_caret_tilt_left@2x.png',
-    'res/text_caret_tilt_right.png',
-    'res/text_caret_tilt_right@1.5x.png',
-    'res/text_caret_tilt_right@2.25x.png',
-    'res/text_caret_tilt_right@2x.png',
-    'res/text_selection_handle.png',
-    'res/text_selection_handle@1.5.png',
-    'res/text_selection_handle@2.png',
-]
--- a/editor/crashtests.list
+++ b/editor/crashtests.list
@@ -1,9 +1,9 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 include libeditor/html/crashtests/crashtests.list
 include libeditor/base/crashtests/crashtests.list
 include libeditor/text/crashtests/crashtests.list
-include composer/src/crashtests/crashtests.list
+include composer/crashtests/crashtests.list
 include txmgr/tests/crashtests/crashtests.list
--- a/editor/libeditor/base/moz.build
+++ b/editor/libeditor/base/moz.build
@@ -31,14 +31,14 @@ UNIFIED_SOURCES += [
     'SplitElementTxn.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../text',
     '/content/base/src',
-    '/editor/txmgr/src',
+    '/editor/txmgr',
     '/extensions/spellcheck/src',
     '/layout/style',
 ]
 
 FINAL_LIBRARY = 'gklayout'
--- a/editor/libeditor/html/moz.build
+++ b/editor/libeditor/html/moz.build
@@ -27,16 +27,16 @@ UNIFIED_SOURCES += [
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../base',
     '../text',
     '/content/base/src',
-    '/editor/txmgr/src',
+    '/editor/txmgr',
     '/layout/generic',
     '/layout/style',
     '/layout/tables',
     '/layout/xul',
 ]
 
 FINAL_LIBRARY = 'gklayout'
--- a/editor/libeditor/text/moz.build
+++ b/editor/libeditor/text/moz.build
@@ -13,16 +13,16 @@ UNIFIED_SOURCES += [
     'nsTextEditUtils.cpp',
 ]
 
 FAIL_ON_WARNINGS = True
 
 LOCAL_INCLUDES += [
     '../base',
     '/content/base/src',
-    '/editor/txmgr/src',
+    '/editor/txmgr',
 ]
 
 FINAL_LIBRARY = 'gklayout'
 
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
 
 MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
deleted file mode 100644
--- a/editor/txmgr/idl/moz.build
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-XPIDL_SOURCES += [
-    'nsITransaction.idl',
-    'nsITransactionList.idl',
-    'nsITransactionListener.idl',
-    'nsITransactionManager.idl',
-]
-
-XPIDL_MODULE = 'txmgr'
-
--- a/editor/txmgr/moz.build
+++ b/editor/txmgr/moz.build
@@ -1,9 +1,32 @@
 # -*- Mode: python; c-basic-offset: 4; 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/.
 
-PARALLEL_DIRS += ['public', 'src', 'idl']
 TEST_TOOL_DIRS += ['tests']
 
+XPIDL_SOURCES += [
+    'nsITransaction.idl',
+    'nsITransactionList.idl',
+    'nsITransactionListener.idl',
+    'nsITransactionManager.idl',
+]
+
+XPIDL_MODULE = 'txmgr'
+
+EXPORTS += [
+    'nsTransactionManagerCID.h',
+]
+
+UNIFIED_SOURCES += [
+    'nsTransactionItem.cpp',
+    'nsTransactionList.cpp',
+    'nsTransactionManager.cpp',
+    'nsTransactionManagerFactory.cpp',
+    'nsTransactionStack.cpp',
+]
+
+FAIL_ON_WARNINGS = True
+
+FINAL_LIBRARY = 'xul'
rename from editor/txmgr/idl/nsITransaction.idl
rename to editor/txmgr/nsITransaction.idl
rename from editor/txmgr/idl/nsITransactionList.idl
rename to editor/txmgr/nsITransactionList.idl
rename from editor/txmgr/idl/nsITransactionListener.idl
rename to editor/txmgr/nsITransactionListener.idl
rename from editor/txmgr/idl/nsITransactionManager.idl
rename to editor/txmgr/nsITransactionManager.idl
rename from editor/txmgr/src/nsTransactionItem.cpp
rename to editor/txmgr/nsTransactionItem.cpp
rename from editor/txmgr/src/nsTransactionItem.h
rename to editor/txmgr/nsTransactionItem.h
rename from editor/txmgr/src/nsTransactionList.cpp
rename to editor/txmgr/nsTransactionList.cpp
rename from editor/txmgr/src/nsTransactionList.h
rename to editor/txmgr/nsTransactionList.h
rename from editor/txmgr/src/nsTransactionManager.cpp
rename to editor/txmgr/nsTransactionManager.cpp
rename from editor/txmgr/src/nsTransactionManager.h
rename to editor/txmgr/nsTransactionManager.h
rename from editor/txmgr/public/nsTransactionManagerCID.h
rename to editor/txmgr/nsTransactionManagerCID.h
rename from editor/txmgr/src/nsTransactionManagerFactory.cpp
rename to editor/txmgr/nsTransactionManagerFactory.cpp
rename from editor/txmgr/src/nsTransactionStack.cpp
rename to editor/txmgr/nsTransactionStack.cpp
rename from editor/txmgr/src/nsTransactionStack.h
rename to editor/txmgr/nsTransactionStack.h
deleted file mode 100644
--- a/editor/txmgr/public/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXPORTS += [
-    'nsTransactionManagerCID.h',
-]
-
deleted file mode 100644
--- a/editor/txmgr/src/moz.build
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-UNIFIED_SOURCES += [
-    'nsTransactionItem.cpp',
-    'nsTransactionList.cpp',
-    'nsTransactionManager.cpp',
-    'nsTransactionManagerFactory.cpp',
-    'nsTransactionStack.cpp',
-]
-
-FAIL_ON_WARNINGS = True
-
-FINAL_LIBRARY = 'xul'
--- a/editor/txtsvc/moz.build
+++ b/editor/txtsvc/moz.build
@@ -1,8 +1,28 @@
 # -*- Mode: python; c-basic-offset: 4; 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/.
 
-PARALLEL_DIRS += ['public', 'src']
+XPIDL_SOURCES += [
+    'nsIInlineSpellChecker.idl',
+    'nsITextServicesFilter.idl',
+]
+
+XPIDL_MODULE = 'txtsvc'
 
+EXPORTS += [
+    'nsISpellChecker.h',
+    'nsITextService.h',
+    'nsITextServicesDocument.h',
+    'nsTextServicesCID.h',
+]
+
+UNIFIED_SOURCES += [
+    'nsFilteredContentIterator.cpp',
+    'nsTextServicesDocument.cpp',
+]
+
+FAIL_ON_WARNINGS = True
+
+FINAL_LIBRARY = 'gklayout'
rename from editor/txtsvc/src/nsFilteredContentIterator.cpp
rename to editor/txtsvc/nsFilteredContentIterator.cpp
rename from editor/txtsvc/src/nsFilteredContentIterator.h
rename to editor/txtsvc/nsFilteredContentIterator.h
rename from editor/txtsvc/public/nsIInlineSpellChecker.idl
rename to editor/txtsvc/nsIInlineSpellChecker.idl
rename from editor/txtsvc/public/nsISpellChecker.h
rename to editor/txtsvc/nsISpellChecker.h
rename from editor/txtsvc/public/nsITextService.h
rename to editor/txtsvc/nsITextService.h
rename from editor/txtsvc/public/nsITextServicesDocument.h
rename to editor/txtsvc/nsITextServicesDocument.h
rename from editor/txtsvc/public/nsITextServicesFilter.idl
rename to editor/txtsvc/nsITextServicesFilter.idl
rename from editor/txtsvc/src/nsTSAtomList.h
rename to editor/txtsvc/nsTSAtomList.h
rename from editor/txtsvc/public/nsTextServicesCID.h
rename to editor/txtsvc/nsTextServicesCID.h
rename from editor/txtsvc/src/nsTextServicesDocument.cpp
rename to editor/txtsvc/nsTextServicesDocument.cpp
rename from editor/txtsvc/src/nsTextServicesDocument.h
rename to editor/txtsvc/nsTextServicesDocument.h
rename from editor/txtsvc/src/nsTextServicesFactory.cpp
rename to editor/txtsvc/nsTextServicesFactory.cpp
deleted file mode 100644
--- a/editor/txtsvc/public/moz.build
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-XPIDL_SOURCES += [
-    'nsIInlineSpellChecker.idl',
-    'nsITextServicesFilter.idl',
-]
-
-XPIDL_MODULE = 'txtsvc'
-
-EXPORTS += [
-    'nsISpellChecker.h',
-    'nsITextService.h',
-    'nsITextServicesDocument.h',
-    'nsTextServicesCID.h',
-]
-
deleted file mode 100644
--- a/editor/txtsvc/src/moz.build
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; 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/.
-
-UNIFIED_SOURCES += [
-    'nsFilteredContentIterator.cpp',
-    'nsTextServicesDocument.cpp',
-]
-
-FAIL_ON_WARNINGS = True
-
-FINAL_LIBRARY = 'gklayout'
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -161,21 +161,21 @@ class TreeLog
 {
 public:
   TreeLog(const std::string& aPrefix = "")
         : mLog(LogOptions::NoNewline),
           mPrefix(aPrefix),
           mDepth(0),
           mStartOfLine(true),
           mConditionedOnPref(false),
-          mPref(nullptr) {}
+          mPrefFunction(nullptr) {}
 
   template <typename T>
   TreeLog& operator<<(const T& aObject) {
-    if (mConditionedOnPref && !*mPref) {
+    if (mConditionedOnPref && !mPrefFunction()) {
       return *this;
     }
     if (mStartOfLine) {
       mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' ');
       mStartOfLine = false;
     }
     mLog << aObject;
     if (EndsInNewline(aObject)) {
@@ -185,27 +185,27 @@ public:
       mStartOfLine = true;
     }
     return *this;
   }
 
   void IncreaseIndent() { ++mDepth; }
   void DecreaseIndent() { --mDepth; }
 
-  void ConditionOnPref(bool* aPref) {
+  void ConditionOnPrefFunction(bool(*aPrefFunction)()) {
     mConditionedOnPref = true;
-    mPref = aPref;
+    mPrefFunction = aPrefFunction;
   }
 private:
   Log<LOG_DEBUG> mLog;
   std::string mPrefix;
   uint32_t mDepth;
   bool mStartOfLine;
   bool mConditionedOnPref;
-  bool* mPref;
+  bool (*mPrefFunction)();
 
   template <typename T>
   static bool EndsInNewline(const T& aObject) {
     return false;
   }
 
   static bool EndsInNewline(const std::string& aString) {
     return !aString.empty() && aString[aString.length() - 1] == '\n';
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -29,30 +29,26 @@
 #define APZCTM_LOG(...)
 // #define APZCTM_LOG(...) printf_stderr("APZCTM: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 float APZCTreeManager::sDPI = 160.0;
 
-// Pref that enables printing of the APZC tree for debugging.
-static bool gPrintApzcTree = false;
-
 APZCTreeManager::APZCTreeManager()
     : mTreeLock("APZCTreeLock"),
       mInOverscrolledApzc(false),
       mRetainedTouchIdentifier(-1),
       mTouchCount(0),
       mApzcTreeLog("apzctree")
 {
   MOZ_ASSERT(NS_IsMainThread());
   AsyncPanZoomController::InitializeGlobalState();
-  Preferences::AddBoolVarCache(&gPrintApzcTree, "apz.printtree", gPrintApzcTree);
-  mApzcTreeLog.ConditionOnPref(&gPrintApzcTree);
+  mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
 }
 
 APZCTreeManager::~APZCTreeManager()
 {
 }
 
 void
 APZCTreeManager::GetAllowedTouchBehavior(WidgetInputEvent* aEvent,
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -144,24 +144,24 @@ ClientCanvasLayer::Initialize(const Data
 }
 
 void
 ClientCanvasLayer::RenderLayer()
 {
   PROFILER_LABEL("ClientCanvasLayer", "RenderLayer",
     js::ProfileEntry::Category::GRAPHICS);
 
+  if (GetMaskLayer()) {
+    ToClientLayer(GetMaskLayer())->RenderLayer();
+  }
+
   if (!IsDirty()) {
     return;
   }
 
-  if (GetMaskLayer()) {
-    ToClientLayer(GetMaskLayer())->RenderLayer();
-  }
-
   if (!mCanvasClient) {
     TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD;
     if (mNeedsYFlip) {
       flags |= TextureFlags::NEEDS_Y_FLIP;
     }
 
     if (!mGLContext) {
       // We don't support locking for buffer surfaces currently
--- a/gfx/layers/ipc/LayerTransactionParent.cpp
+++ b/gfx/layers/ipc/LayerTransactionParent.cpp
@@ -534,16 +534,19 @@ LayerTransactionParent::RecvUpdate(const
       host->SetCompositorID(mLayerManager->GetCompositor()->GetCompositorID());
       break;
     }
     default:
       NS_RUNTIMEABORT("not reached");
     }
   }
 
+  mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
+                                            isFirstPaint, scheduleComposite, paintSequenceNumber);
+
   {
     AutoResolveRefLayers resolve(mShadowLayersManager->GetCompositionManager(this));
     layer_manager()->EndTransaction(nullptr, nullptr, LayerManager::END_NO_IMMEDIATE_REDRAW);
   }
 
   if (reply) {
     reply->SetCapacity(replyv.size());
     if (replyv.size() > 0) {
@@ -553,19 +556,16 @@ LayerTransactionParent::RecvUpdate(const
 
   if (!IsSameProcess()) {
     // Ensure that any pending operations involving back and front
     // buffers have completed, so that neither process stomps on the
     // other's buffer contents.
     LayerManagerComposite::PlatformSyncBeforeReplyUpdate();
   }
 
-  mShadowLayersManager->ShadowLayersUpdated(this, aTransactionId, targetConfig,
-                                            isFirstPaint, scheduleComposite, paintSequenceNumber);
-
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   int compositeTime = (int)(mozilla::TimeStamp::Now() - updateStart).ToMilliseconds();
   if (compositeTime > 15) {
     printf_stderr("Compositor: Layers update took %i ms (blocking gecko).\n", compositeTime);
   }
 #endif
 
   return true;
--- a/gfx/layers/opengl/CompositorOGL.cpp
+++ b/gfx/layers/opengl/CompositorOGL.cpp
@@ -43,16 +43,20 @@
 #include "GLReadTexImageHelper.h"
 #include "TiledLayerBuffer.h"           // for TiledLayerComposer
 #include "HeapCopyOfStackArray.h"
 
 #if MOZ_ANDROID_OMTC
 #include "TexturePoolOGL.h"
 #endif
 
+#ifdef XP_MACOSX
+#include "nsCocoaFeatures.h"
+#endif
+
 #include "GeckoProfiler.h"
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 #include "libdisplay/GonkDisplay.h"     // for GonkDisplay
 #include <ui/Fence.h>
 #endif
 
 #define BUFFER_OFFSET(i) ((char *)nullptr + (i))
@@ -1242,16 +1246,29 @@ CompositorOGL::DrawQuad(const Rect& aRec
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       // Pass 2.
       gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE,
                                LOCAL_GL_ONE, LOCAL_GL_ONE);
+
+#ifdef XP_MACOSX
+      if (gl()->WorkAroundDriverBugs() &&
+          gl()->Vendor() == GLVendor::NVIDIA &&
+          !nsCocoaFeatures::OnMavericksOrLater()) {
+        // Bug 987497: With some GPUs the nvidia driver on 10.8 and below
+        // won't pick up the TexturePass2 uniform change below if we don't do
+        // something to force it. Re-activating the shader seems to be one way
+        // of achieving that.
+        program->Activate();
+      }
+#endif
+
       program->SetTexturePass2(true);
       BindAndDrawQuadWithTextureRect(program,
                                      aRect,
                                      effectComponentAlpha->mTextureCoords,
                                      effectComponentAlpha->mOnBlack);
 
       mGLContext->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE_MINUS_SRC_ALPHA,
                                      LOCAL_GL_ONE, LOCAL_GL_ONE);
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -1,18 +1,30 @@
 #!/usr/bin/env python
 
 import os
 
 import locale
 locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
 
 header = """
-# Please note this file is autogenerated from generate_mozbuild.py, so do not modify it directly
-
+#
+#   #####   #######           #     #     #     #     #     #
+# ##     #  #     #          # #    #  #  #    # #     #   #
+# ##        #     #         #   #   #  #  #   #   #     # #
+# ##  ####  #     #        #     #  #  #  #  #     #     #
+# ##     #  #     #        #######  #  #  #  #######     #      ###
+# ##     #  #     #        #     #  #  #  #  #     #     #      ###
+# # #####   #######        #     #   ## ##   #     #     #      ###
+#
+# Seriously. You shouldn't even be looking at this file unless you're
+# debugging generate_mozbuild.py.
+#
+# DO NOT MODIFY THIS FILE IT IS AUTOGENERATED.
+#
 """
 
 footer = """
 
 # left out of UNIFIED_SOURCES for now; that's not C++ anyway, nothing else to unify it with
 if not CONFIG['INTEL_ARCHITECTURE'] and CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
     SOURCES += [
         'trunk/src/opts/memset.arm.S',
@@ -285,17 +297,59 @@ def write_cflags(f, values, subsearch, c
   if len(val_list) == 0:
     return
 
   for val in val_list:
     if val.find(subsearch) > 0:
       write_indent(indent)
       f.write("SOURCES[\'" + val + "\'].flags += [\'" + cflag + "\']\n")
 
+def write_sources(f, values, indent):
 
+  # Unfortunately for now the gpu and pathops directories are
+  # non-unifiable. Keep track of this and fix it.
+  unified_blacklist = [
+    '_SSE',
+    '_SSSE',
+    '_neon',
+    'FontHost',
+    'SkBitmapProcState_matrixProcs.cpp',
+    'SkBlitter_A8.cpp',
+    'SkBlitter_ARGB32.cpp',
+    'SkBlitter_RGB16.cpp',
+    'SkBlitter_Sprite.cpp',
+    'SkScan_Antihair.cpp',
+    'SkCondVar.cpp',
+    'SkParse.cpp',
+    'GrAddPathRenderers_default.cpp',
+    'GrDistanceFieldTextContext.cpp',
+    'SkSHA1.cpp',
+    'SkMD5.cpp',
+  ]
+
+  def isblacklisted(value):
+    for item in unified_blacklist:
+      if value.find(item) >= 0:
+        return True
+
+    return False
+
+  sources = {}
+  sources['nonunified'] = set()
+  sources['unified'] = set()
+
+  for item in values:
+    if isblacklisted(item):
+      sources['nonunified'].add(item)
+    else:
+      sources['unified'].add(item)
+
+  write_list(f, "UNIFIED_SOURCES", sources['unified'], indent)
+  write_list(f, "SOURCES", sources['nonunified'], indent)
+  
 def write_list(f, name, values, indent):
   def write_indent(indent):
     for _ in range(indent):
         f.write(' ')
 
   val_list = uniq(sorted(map(lambda val: val.replace('../', 'trunk/'), values), key=lambda x: x.lower()))
 
   if len(val_list) == 0:
@@ -313,46 +367,45 @@ def write_list(f, name, values, indent):
 def write_mozbuild(includes, sources):
   filename = 'moz.build'
   f = open(filename, 'w')
 
   f.write(header)
 
   write_list(f, 'EXPORTS.skia', includes, 0)
 
-  write_list(f, 'SOURCES', sources['common'], 0)
+  write_sources(f, sources['common'], 0)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):\n")
-  write_list(f, 'SOURCES', sources['android'], 4)
+  write_sources(f, sources['android'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':\n")
-  write_list(f, 'SOURCES', sources['mac'], 4)
+  write_sources(f, sources['mac'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_GTK']:\n")
-  write_list(f, 'SOURCES', sources['linux'], 4)
+  write_sources(f, sources['linux'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':\n")
-  write_list(f, 'SOURCES', sources['linux'], 4)
+  write_sources(f, sources['linux'], 4)
 
   f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':\n")
-  write_list(f, 'SOURCES', sources['win'], 4)
+  write_sources(f, sources['win'], 4)
 
-  f.write("\n\n")
   f.write("if CONFIG['INTEL_ARCHITECTURE']:\n")
-  write_list(f, 'SOURCES', sources['intel'], 4)
+  write_sources(f, sources['intel'], 4)
 
   f.write("elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:\n")
-  write_list(f, 'SOURCES', sources['arm'], 4)
+  write_sources(f, sources['arm'], 4)
 
   f.write("    if CONFIG['BUILD_ARM_NEON']:\n")
   write_list(f, 'SOURCES', sources['neon'], 8)
   write_cflags(f, sources['neon'], 'neon', '-mfpu=neon', 8)
 
   f.write("else:\n")
-  write_list(f, 'SOURCES', sources['none'], 4)
+  write_sources(f, sources['none'], 4)
 
   f.write(footer)
 
   f.close()
 
   print 'Wrote ' + filename
 
 def main():
--- a/gfx/skia/moz.build
+++ b/gfx/skia/moz.build
@@ -1,11 +1,23 @@
 
-# Please note this file is autogenerated from generate_mozbuild.py, so do not modify it directly
-
+#
+#   #####   #######           #     #     #     #     #     #
+# ##     #  #     #          # #    #  #  #    # #     #   #
+# ##        #     #         #   #   #  #  #   #   #     # #
+# ##  ####  #     #        #     #  #  #  #  #     #     #
+# ##     #  #     #        #######  #  #  #  #######     #      ###
+# ##     #  #     #        #     #  #  #  #  #     #     #      ###
+# # #####   #######        #     #   ## ##   #     #     #      ###
+#
+# Seriously. You shouldn't even be looking at this file unless you're
+# debugging generate_mozbuild.py.
+#
+# DO NOT MODIFY THIS FILE IT IS AUTOGENERATED.
+#
 EXPORTS.skia += [
     'trunk/include/animator/SkAnimator.h',
     'trunk/include/animator/SkAnimatorView.h',
     'trunk/include/config/SkUserConfig.h',
     'trunk/include/core/SkAdvancedTypefaceMetrics.h',
     'trunk/include/core/SkAnnotation.h',
     'trunk/include/core/SkBitmap.h',
     'trunk/include/core/SkBitmapDevice.h',
@@ -356,17 +368,16 @@ UNIFIED_SOURCES += [
     'trunk/src/core/SkError.cpp',
     'trunk/src/core/SkFilterProc.cpp',
     'trunk/src/core/SkFilterShader.cpp',
     'trunk/src/core/SkFlattenable.cpp',
     'trunk/src/core/SkFlattenableSerialization.cpp',
     'trunk/src/core/SkFloat.cpp',
     'trunk/src/core/SkFloatBits.cpp',
     'trunk/src/core/SkFontDescriptor.cpp',
-    'trunk/src/core/SkFontHost.cpp',
     'trunk/src/core/SkFontStream.cpp',
     'trunk/src/core/SkGeometry.cpp',
     'trunk/src/core/SkGlyphCache.cpp',
     'trunk/src/core/SkGraphics.cpp',
     'trunk/src/core/SkImageFilter.cpp',
     'trunk/src/core/SkImageInfo.cpp',
     'trunk/src/core/SkInstCnt.cpp',
     'trunk/src/core/SkLineClipper.cpp',
@@ -661,124 +672,135 @@ UNIFIED_SOURCES += [
     'trunk/src/utils/SkDeferredCanvas.cpp',
     'trunk/src/utils/SkDumpCanvas.cpp',
     'trunk/src/utils/SkEventTracer.cpp',
     'trunk/src/utils/SkFrontBufferedStream.cpp',
     'trunk/src/utils/SkGatherPixelRefsAndRects.cpp',
     'trunk/src/utils/SkInterpolator.cpp',
     'trunk/src/utils/SkLayer.cpp',
     'trunk/src/utils/SkMatrix44.cpp',
-    'trunk/src/utils/SkMD5.cpp',
     'trunk/src/utils/SkMeshUtils.cpp',
     'trunk/src/utils/SkNinePatch.cpp',
     'trunk/src/utils/SkNullCanvas.cpp',
     'trunk/src/utils/SkNWayCanvas.cpp',
     'trunk/src/utils/SkOSFile.cpp',
     'trunk/src/utils/SkParseColor.cpp',
     'trunk/src/utils/SkParsePath.cpp',
     'trunk/src/utils/SkPathUtils.cpp',
     'trunk/src/utils/SkPictureUtils.cpp',
     'trunk/src/utils/SkProxyCanvas.cpp',
     'trunk/src/utils/SkRTConf.cpp',
-    'trunk/src/utils/SkSHA1.cpp',
     'trunk/src/utils/SkUnitMappers.cpp',
 ]
 SOURCES += [
     'trunk/src/core/SkBitmapProcState_matrixProcs.cpp',
     'trunk/src/core/SkBlitter_A8.cpp',
     'trunk/src/core/SkBlitter_ARGB32.cpp',
     'trunk/src/core/SkBlitter_RGB16.cpp',
     'trunk/src/core/SkBlitter_Sprite.cpp',
+    'trunk/src/core/SkFontHost.cpp',
     'trunk/src/core/SkScan_Antihair.cpp',
     'trunk/src/gpu/GrAddPathRenderers_default.cpp',
     'trunk/src/gpu/GrDistanceFieldTextContext.cpp',
     'trunk/src/utils/SkCondVar.cpp',
+    'trunk/src/utils/SkMD5.cpp',
     'trunk/src/utils/SkParse.cpp',
+    'trunk/src/utils/SkSHA1.cpp',
 ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/images/SkImageRef_ashmem.cpp',
         'trunk/src/ports/SkDebug_android.cpp',
-        'trunk/src/ports/SkFontHost_android_old.cpp',
-        'trunk/src/ports/SkFontHost_cairo.cpp',
-        'trunk/src/ports/SkFontHost_FreeType.cpp',
-        'trunk/src/ports/SkFontHost_FreeType_common.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkPurgeableMemoryBlock_android.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
         'trunk/src/utils/android/ashmem.cpp',
         'trunk/src/utils/SkThreadUtils_pthread.cpp',
     ]
+    SOURCES += [
+        'trunk/src/ports/SkFontHost_android_old.cpp',
+        'trunk/src/ports/SkFontHost_cairo.cpp',
+        'trunk/src/ports/SkFontHost_FreeType.cpp',
+        'trunk/src/ports/SkFontHost_FreeType_common.cpp',
+    ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/ports/SkDebug_stdio.cpp',
-        'trunk/src/ports/SkFontHost_mac.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkPurgeableMemoryBlock_mac.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
         'trunk/src/utils/mac/SkCreateCGImageRef.cpp',
         'trunk/src/utils/mac/SkStream_mac.cpp',
         'trunk/src/utils/SkThreadUtils_pthread.cpp',
     ]
+    SOURCES += [
+        'trunk/src/ports/SkFontHost_mac.cpp',
+    ]
 if CONFIG['MOZ_WIDGET_GTK']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/ports/SkDebug_stdio.cpp',
-        'trunk/src/ports/SkFontHost_cairo.cpp',
-        'trunk/src/ports/SkFontHost_FreeType.cpp',
-        'trunk/src/ports/SkFontHost_FreeType_common.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
         'trunk/src/utils/SkThreadUtils_pthread.cpp',
     ]
-if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
     SOURCES += [
-        'trunk/src/ports/SkDebug_stdio.cpp',
         'trunk/src/ports/SkFontHost_cairo.cpp',
         'trunk/src/ports/SkFontHost_FreeType.cpp',
         'trunk/src/ports/SkFontHost_FreeType_common.cpp',
+    ]
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
+    UNIFIED_SOURCES += [
+        'trunk/src/ports/SkDebug_stdio.cpp',
         'trunk/src/ports/SkOSFile_posix.cpp',
         'trunk/src/ports/SkTime_Unix.cpp',
         'trunk/src/ports/SkTLS_pthread.cpp',
         'trunk/src/utils/SkThreadUtils_pthread.cpp',
     ]
+    SOURCES += [
+        'trunk/src/ports/SkFontHost_cairo.cpp',
+        'trunk/src/ports/SkFontHost_FreeType.cpp',
+        'trunk/src/ports/SkFontHost_FreeType_common.cpp',
+    ]
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/ports/SkDebug_win.cpp',
-        'trunk/src/ports/SkFontHost_win.cpp',
         'trunk/src/ports/SkFontMgr_default_gdi.cpp',
         'trunk/src/ports/SkOSFile_win.cpp',
         'trunk/src/ports/SkTime_win.cpp',
         'trunk/src/ports/SkTLS_win.cpp',
         'trunk/src/utils/SkThreadUtils_win.cpp',
         'trunk/src/utils/win/SkAutoCoInitialize.cpp',
         'trunk/src/utils/win/SkDWriteFontFileStream.cpp',
         'trunk/src/utils/win/SkDWriteGeometrySink.cpp',
         'trunk/src/utils/win/SkHRESULT.cpp',
         'trunk/src/utils/win/SkIStream.cpp',
     ]
-
-
+    SOURCES += [
+        'trunk/src/ports/SkFontHost_win.cpp',
+    ]
 if CONFIG['INTEL_ARCHITECTURE']:
+    UNIFIED_SOURCES += [
+        'trunk/src/opts/SkXfermode_opts_none.cpp',
+    ]
     SOURCES += [
         'trunk/src/opts/opts_check_SSE2.cpp',
         'trunk/src/opts/SkBitmapFilter_opts_SSE2.cpp',
         'trunk/src/opts/SkBitmapProcState_opts_SSE2.cpp',
         'trunk/src/opts/SkBitmapProcState_opts_SSSE3.cpp',
         'trunk/src/opts/SkBlitRect_opts_SSE2.cpp',
         'trunk/src/opts/SkBlitRow_opts_SSE2.cpp',
         'trunk/src/opts/SkBlurImage_opts_SSE2.cpp',
         'trunk/src/opts/SkMorphology_opts_SSE2.cpp',
         'trunk/src/opts/SkUtils_opts_SSE2.cpp',
-        'trunk/src/opts/SkXfermode_opts_none.cpp',
     ]
 elif CONFIG['CPU_ARCH'] == 'arm' and CONFIG['GNU_CC']:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/core/SkUtilsArm.cpp',
         'trunk/src/opts/SkBitmapProcState_opts_arm.cpp',
         'trunk/src/opts/SkBlitMask_opts_arm.cpp',
         'trunk/src/opts/SkBlitRow_opts_arm.cpp',
         'trunk/src/opts/SkBlurImage_opts_arm.cpp',
         'trunk/src/opts/SkMorphology_opts_arm.cpp',
         'trunk/src/opts/SkUtils_opts_arm.cpp',
         'trunk/src/opts/SkXfermode_opts_arm.cpp',
@@ -796,17 +818,17 @@ elif CONFIG['CPU_ARCH'] == 'arm' and CON
         SOURCES['trunk/src/opts/SkBitmapProcState_arm_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkBitmapProcState_matrixProcs_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkBlitMask_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkBlitRow_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkBlurImage_opts_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkMorphology_opts_neon.cpp'].flags += ['-mfpu=neon']
         SOURCES['trunk/src/opts/SkXfermode_opts_arm_neon.cpp'].flags += ['-mfpu=neon']
 else:
-    SOURCES += [
+    UNIFIED_SOURCES += [
         'trunk/src/opts/SkBitmapProcState_opts_none.cpp',
         'trunk/src/opts/SkBlitMask_opts_none.cpp',
         'trunk/src/opts/SkBlitRow_opts_none.cpp',
         'trunk/src/opts/SkBlurImage_opts_none.cpp',
         'trunk/src/opts/SkMorphology_opts_none.cpp',
         'trunk/src/opts/SkUtils_opts_none.cpp',
         'trunk/src/opts/SkXfermode_opts_none.cpp',
         'trunk/src/ports/SkDiscardableMemory_none.cpp',
--- a/gfx/thebes/gfx3DMatrix.h
+++ b/gfx/thebes/gfx3DMatrix.h
@@ -6,17 +6,17 @@
 #ifndef GFX_3DMATRIX_H
 #define GFX_3DMATRIX_H
 
 #include <gfxTypes.h>
 #include <gfxPoint3D.h>
 #include <gfxPointH3D.h>
 #include <gfxQuad.h>
 
-struct gfxMatrix;
+class gfxMatrix;
 
 /**
  * This class represents a 3D transformation. The matrix is laid
  * out as follows:
  *
  * _11 _12 _13 _14
  * _21 _22 _23 _24
  * _31 _32 _33 _34
--- a/gfx/thebes/gfxBlur.cpp
+++ b/gfx/thebes/gfxBlur.cpp
@@ -1,16 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * 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 "gfxBlur.h"
 #include "gfxContext.h"
-#include "gfxImageSurface.h"
 #include "gfxPlatform.h"
 
 #include "mozilla/gfx/Blur.h"
 #include "mozilla/gfx/2D.h"
 #include "nsExpirationTracker.h"
 #include "nsClassHashtable.h"
 
 using namespace mozilla;
@@ -65,25 +64,17 @@ gfxAlphaBoxBlur::Init(const gfxRect& aRe
     mData = new unsigned char[blurDataSize];
     memset(mData, 0, blurDataSize);
 
     mozilla::RefPtr<DrawTarget> dt =
         gfxPlatform::GetPlatform()->CreateDrawTargetForData(mData, size,
                                                             mBlur->GetStride(),
                                                             SurfaceFormat::A8);
     if (!dt) {
-        nsRefPtr<gfxImageSurface> image =
-            new gfxImageSurface(mData,
-                                gfxIntSize(size.width, size.height),
-                                mBlur->GetStride(),
-                                gfxImageFormat::A8);
-        dt = Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), size);
-        if (!dt) {
-            return nullptr;
-        }
+        return nullptr;
     }
 
     IntRect irect = mBlur->GetRect();
     gfxPoint topleft(irect.TopLeft().x, irect.TopLeft().y);
 
     mContext = new gfxContext(dt);
     mContext->Translate(-topleft);
 
--- a/gfx/thebes/gfxBlur.h
+++ b/gfx/thebes/gfxBlur.h
@@ -11,17 +11,17 @@
 #include "nsAutoPtr.h"
 #include "gfxPoint.h"
 #include "mozilla/RefPtr.h"
 
 class gfxContext;
 struct gfxRect;
 struct gfxRGBA;
 struct gfxCornerSizes;
-struct gfxMatrix;
+class gfxMatrix;
 
 namespace mozilla {
   namespace gfx {
     class AlphaBoxBlur;
     class SourceSurface;
     class DrawTarget;
   }
 }
--- a/gfx/thebes/gfxMatrix.h
+++ b/gfx/thebes/gfxMatrix.h
@@ -25,22 +25,22 @@
  *
  * So, transforming a point (x, y) results in:
  *
  *           / a  b  0 \   / a * x + c * y + tx \ T
  * (x y 1) * | c  d  0 | = | b * x + d * y + ty |
  *           \ tx ty 1 /   \         1          /
  *
  */
-struct gfxMatrix {
+class gfxMatrix {
+public:
     double _11; double _12;
     double _21; double _22;
     double _31; double _32;
 
-public:
     /**
      * Initializes this matrix as the identity matrix.
      */
     gfxMatrix() { Reset(); }
 
     /**
      * Initializes the matrix from individual components. See the class
      * description for the layout of the matrix.
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1013,21 +1013,28 @@ gfxPlatform::CreateOffscreenContentDrawT
   NS_ASSERTION(mPreferredCanvasBackend != BackendType::NONE, "No backend.");
   return CreateDrawTargetForBackend(mContentBackend, aSize, aFormat);
 }
 
 TemporaryRef<DrawTarget>
 gfxPlatform::CreateDrawTargetForData(unsigned char* aData, const IntSize& aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   NS_ASSERTION(mContentBackend != BackendType::NONE, "No backend.");
-  if (mContentBackend == BackendType::CAIRO) {
-    nsRefPtr<gfxImageSurface> image = new gfxImageSurface(aData, gfxIntSize(aSize.width, aSize.height), aStride, SurfaceFormatToImageFormat(aFormat));
-    return Factory::CreateDrawTargetForCairoSurface(image->CairoSurface(), aSize);
+
+  RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(mContentBackend,
+                                                           aData, aSize,
+                                                           aStride, aFormat);
+  if (!dt) {
+    // Factory::CreateDrawTargetForData does not support mContentBackend; retry
+    // with BackendType::CAIRO:
+    dt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
+                                          aData, aSize,
+                                          aStride, aFormat);
   }
-  return Factory::CreateDrawTargetForData(mContentBackend, aData, aSize, aStride, aFormat);
+  return dt.forget();
 }
 
 /* static */ BackendType
 gfxPlatform::BackendTypeForName(const nsCString& aName)
 {
   if (aName.EqualsLiteral("cairo"))
     return BackendType::CAIRO;
   if (aName.EqualsLiteral("skia"))
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -127,16 +127,17 @@ private:
   DECL_GFX_PREF(Live, "apz.overscroll.fling_friction",         APZOverscrollFlingFriction, float, 0.02f);
   DECL_GFX_PREF(Live, "apz.overscroll.fling_stopped_threshold", APZOverscrollFlingStoppedThreshold, float, 0.4f);
   DECL_GFX_PREF(Live, "apz.overscroll.clamping",               APZOverscrollClamping, float, 0.5f);
   DECL_GFX_PREF(Live, "apz.overscroll.z_effect",               APZOverscrollZEffect, float, 0.2f);
   DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_stiffness", APZOverscrollSnapBackSpringStiffness, float, 0.6f);
   DECL_GFX_PREF(Live, "apz.overscroll.snap_back.spring_friction", APZOverscrollSnapBackSpringFriction, float, 0.1f);
   DECL_GFX_PREF(Live, "apz.overscroll.snap_back.mass",         APZOverscrollSnapBackMass, float, 1000.0f);
   DECL_GFX_PREF(Live, "apz.pan_repaint_interval",              APZPanRepaintInterval, int32_t, 250);
+  DECL_GFX_PREF(Live, "apz.printtree",                         APZPrintTree, bool, false);
   DECL_GFX_PREF(Live, "apz.subframe.enabled",                  APZSubframeEnabled, bool, false);
   DECL_GFX_PREF(Once, "apz.test.logging_enabled",              APZTestLoggingEnabled, bool, false);
   DECL_GFX_PREF(Live, "apz.touch_start_tolerance",             APZTouchStartTolerance, float, 1.0f/4.5f);
   DECL_GFX_PREF(Live, "apz.use_paint_duration",                APZUsePaintDuration, bool, true);
   DECL_GFX_PREF(Live, "apz.velocity_bias",                     APZVelocityBias, float, 1.0f);
   DECL_GFX_PREF(Live, "apz.velocity_relevance_time_ms",        APZVelocityRelevanceTime, uint32_t, 150);
   DECL_GFX_PREF(Live, "apz.x_skate_size_multiplier",           APZXSkateSizeMultiplier, float, 1.5f);
   DECL_GFX_PREF(Live, "apz.x_stationary_size_multiplier",      APZXStationarySizeMultiplier, float, 3.0f);
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -149,16 +149,23 @@ interface imgIContainer : nsISupports
   const long FLAG_HIGH_QUALITY_SCALING = 0x10;
   /**
    * Can be passed to GetFrame when the caller wants a DataSourceSurface
    * instead of a hardware accelerated surface. This can be important for
    * performance (by avoiding an upload to/readback from the GPU) when the
    * caller knows they want a SourceSurface of type DATA.
    */
   const long FLAG_WANT_DATA_SURFACE = 0x20;
+  /**
+   * Forces drawing to happen rather than taking cached rendering from the
+   * surface cache. This is used when we are printing, for example, where we
+   * want the vector commands from VectorImages to end up in the PDF output
+   * rather than a cached rendering at screen resolution.
+   */
+  const long FLAG_BYPASS_SURFACE_CACHE = 0x40;
 
   /**
     * Constants for specifying various "special" frames.
     *
     * FRAME_FIRST: The first frame
     * FRAME_CURRENT: The current frame
     *
     * FRAME_MAX_VALUE should be set to the value of the maximum constant above,
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -854,21 +854,26 @@ VectorImage::Draw(gfxContext* aContext,
                                                 : mSVGDocumentWrapper->GetCurrentTime();
   AutoSVGRenderingState autoSVGState(aSVGContext, animTime,
                                      mSVGDocumentWrapper->GetRootSVGElem());
 
   // Pack up the drawing parameters.
   SVGDrawingParameters params(aContext, aFilter, aUserSpaceToImageSpace, aFill,
                               aSubimage, aViewportSize, aSVGContext, animTime, aFlags);
 
-  // Check the cache.
-  nsRefPtr<gfxDrawable> drawable =
-    SurfaceCache::Lookup(ImageKey(this),
-                         SurfaceKey(params.imageRect.Size(), params.scale,
-                                    aSVGContext, animTime, aFlags));
+  // Check the cache. (The FLAG_BYPASS_SURFACE_CACHE check here is just an
+  // optimization since the flags are part of the cache key and we never put
+  // surfaces in the cache if the flags contain FLAG_BYPASS_SURFACE_CACHE.)
+  nsRefPtr<gfxDrawable> drawable;
+  if (!(aFlags & FLAG_BYPASS_SURFACE_CACHE)) {
+    drawable =
+      SurfaceCache::Lookup(ImageKey(this),
+                           SurfaceKey(params.imageRect.Size(), params.scale,
+                                      aSVGContext, animTime, aFlags));
+  }
 
   // Draw.
   if (drawable) {
     Show(drawable, params);
   } else {
     CreateDrawableAndShow(params);
   }
 
@@ -885,23 +890,23 @@ VectorImage::CreateDrawableAndShow(const
     new SVGDrawingCallback(mSVGDocumentWrapper,
                            nsIntRect(nsIntPoint(0, 0), aParams.viewportSize),
                            aParams.scale,
                            aParams.flags);
 
   nsRefPtr<gfxDrawable> svgDrawable =
     new gfxCallbackDrawable(cb, ThebesIntSize(aParams.imageRect.Size()));
 
-  // Refuse to cache animated images.
-  // XXX(seth): We may remove this restriction in bug 922893.
-  if (mHaveAnimations)
-    return Show(svgDrawable, aParams);
-
-  // If the image is too big to fit in the cache, don't go any further.
-  if (!SurfaceCache::CanHold(aParams.imageRect.Size()))
+  bool bypassCache = bool(aParams.flags & FLAG_BYPASS_SURFACE_CACHE) ||
+                     // Refuse to cache animated images:
+                     // XXX(seth): We may remove this restriction in bug 922893.
+                     mHaveAnimations ||
+                     // The image is too big to fit in the cache:
+                     !SurfaceCache::CanHold(aParams.imageRect.Size());
+  if (bypassCache)
     return Show(svgDrawable, aParams);
 
   // Try to create an offscreen surface.
   mozilla::RefPtr<mozilla::gfx::DrawTarget> target =
    gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(aParams.imageRect.Size(), gfx::SurfaceFormat::B8G8R8A8);
 
   // If we couldn't create the draw target, it was probably because it would end
   // up way too big. Generally it also wouldn't fit in the cache, but the prefs
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -875,20 +875,20 @@ GetSavedFrameCount(JSContext *cx, unsign
     args.rval().setNumber(cx->compartment()->savedStacks().count());
     return true;
 }
 
 static bool
 SaveStack(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    Rooted<SavedFrame*> frame(cx);
-    if (!cx->compartment()->savedStacks().saveCurrentStack(cx, &frame))
+    Rooted<JSObject*> stack(cx);
+    if (!JS::CaptureCurrentStack(cx, &stack))
         return false;
-    args.rval().setObject(*frame.get());
+    args.rval().setObject(*stack);
     return true;
 }
 
 static bool
 EnableTrackAllocations(JSContext *cx, unsigned argc, jsval *vp)
 {
     SetObjectMetadataCallback(cx, SavedStacksMetadataCallback);
     return true;
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1438,16 +1438,17 @@ case "$target" in
                 _BAD_COMPILER=,_BAD_COMPILER=1)
             if test -n "$_BAD_COMPILER"; then
                 AC_MSG_RESULT([no])
                 AC_MSG_ERROR([IBM XLC/C++ 9.0.0.7 or higher is required to build.])
             else
                 AC_MSG_RESULT([yes])
             fi
             AC_LANG_RESTORE
+            TARGET_COMPILER_ABI="ibmc"
             CC_VERSION=`lslpp -Lcq vac.C 2>/dev/null | awk -F: '{ print $3 }'`
             CXX_VERSION=`lslpp -Lcq vacpp.cmp.core 2>/dev/null | awk -F: '{ print $3 }'`
         fi
     fi
     case "${target_os}" in
     aix4.1*)
         DLL_SUFFIX='_shr.a'
         ;;
@@ -1615,16 +1616,17 @@ ia64*-hpux*)
         DLL_PREFIX=
         IMPORT_LIB_SUFFIX=dll.a
 
         # We use mix of both POSIX and Win32 printf format across the tree, so format
         # warnings are useless on mingw.
         MOZ_C_SUPPORTS_WARNING(-Wno-, format, ac_c_has_wno_format)
         MOZ_CXX_SUPPORTS_WARNING(-Wno-, format, ac_cxx_has_wno_format)
     else
+        TARGET_COMPILER_ABI=msvc
         HOST_CC='$(CC)'
         HOST_CXX='$(CXX)'
         HOST_LD='$(LD)'
         if test "$AS_BIN"; then
             AS="$(basename "$AS_BIN")"
         fi
         AR='lib'
         AR_FLAGS='-NOLOGO -OUT:$@'
@@ -1849,16 +1851,17 @@ ia64*-hpux*)
        AR_LIST="$AR t"
        AR_EXTRACT="$AR x"
        AR_DELETE="$AR d"
        AR='$(CXX) -xar'
        AR_FLAGS='-o $@'
        AS='/usr/ccs/bin/as'
        ASFLAGS="$ASFLAGS -K PIC -L -P -D_ASM -D__STDC__=0"
        AS_DASH_C_FLAG=''
+       TARGET_COMPILER_ABI="sunc"
        CC_VERSION=`$CC -V 2>&1 | grep '^cc:' 2>/dev/null | $AWK -F\: '{ print $2 }'`
        CXX_VERSION=`$CXX -V 2>&1 | grep '^CC:' 2>/dev/null | $AWK -F\: '{ print $2 }'`
        AC_MSG_CHECKING([for Sun C++ compiler version >= 5.9])
        AC_LANG_SAVE
        AC_LANG_CPLUSPLUS
        AC_TRY_COMPILE([],
            [#if (__SUNPRO_CC < 0x590)
            #error "Denied"
@@ -2493,16 +2496,18 @@ if test "$GNU_CC"; then
                         ac_cv_gcc_arm_eabi="no")])
     if test "$ac_cv_gcc_arm_eabi" = "yes"; then
         HAVE_ARM_EABI=1
         ARM_ABI_PREFIX=eabi-
     else
         ARM_ABI_PREFIX=oabi-
     fi
   fi
+
+  TARGET_COMPILER_ABI="${TARGET_COMPILER_ABI-${ARM_ABI_PREFIX}gcc3}"
 fi
 
 dnl Check to see if we can resolve ambiguity with |using|.
 AC_CACHE_CHECK(whether the C++ \"using\" keyword resolves ambiguity,
                ac_cv_cpp_ambiguity_resolving_using,
                [AC_TRY_COMPILE(class X {
                                  public: int go(const X&) {return 3;}
                                          int jo(const X&) {return 3;}
@@ -2649,16 +2654,21 @@ AC_CACHE_CHECK(for LC_MESSAGES,
 				ac_cv_i18n_lc_messages=no)])
 if test "$ac_cv_i18n_lc_messages" = yes; then
    AC_DEFINE(HAVE_I18N_LC_MESSAGES)
 fi
 
 AC_HAVE_FUNCS(localeconv)
 fi # ! SKIP_COMPILER_CHECKS
 
+TARGET_XPCOM_ABI=
+if test -n "${CPU_ARCH}" -a -n "${TARGET_COMPILER_ABI}"; then
+    TARGET_XPCOM_ABI="${CPU_ARCH}-${TARGET_COMPILER_ABI}"
+fi
+
 dnl Mozilla specific options
 dnl ========================================================
 dnl The macros used for command line options
 dnl are defined in build/autoconf/altoptions.m4.
 
 dnl If the compiler supports these attributes, define them as
 dnl convenience macros.
 if test "$ac_cv_attribute_malloc" = yes ; then
@@ -3869,16 +3879,17 @@ AC_SUBST(HOST_NSPR_MDCPUCFG)
 AC_SUBST(HOST_BIN_SUFFIX)
 AC_SUBST(HOST_OS_ARCH)
 
 AC_SUBST(TARGET_CPU)
 AC_SUBST(TARGET_VENDOR)
 AC_SUBST(TARGET_OS)
 AC_SUBST(TARGET_NSPR_MDCPUCFG)
 AC_SUBST(TARGET_MD_ARCH)
+AC_SUBST(TARGET_XPCOM_ABI)
 AC_SUBST(OS_TARGET)
 AC_SUBST(OS_ARCH)
 AC_SUBST(OS_RELEASE)
 AC_SUBST(OS_TEST)
 AC_SUBST(CPU_ARCH)
 AC_SUBST(INTEL_ARCHITECTURE)
 
 AC_SUBST(WRAP_LDFLAGS)
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -4823,23 +4823,47 @@ Parser<ParseHandler>::yieldExpression()
 
     switch (pc->generatorKind()) {
       case StarGenerator:
       {
         JS_ASSERT(pc->sc->isFunctionBox());
 
         pc->lastYieldOffset = begin;
 
-        ParseNodeKind kind = tokenStream.matchToken(TOK_MUL) ? PNK_YIELD_STAR : PNK_YIELD;
-
-        // ES6 generators require a value.
-        Node exprNode = assignExpr();
-        if (!exprNode)
+        Node exprNode;
+        ParseNodeKind kind = PNK_YIELD;
+        switch (tokenStream.peekTokenSameLine(TokenStream::Operand)) {
+          case TOK_ERROR:
             return null();
-
+          // TOK_EOL is special; it implements the [no LineTerminator here]
+          // quirk in the grammar.
+          case TOK_EOL:
+          // The rest of these make up the complete set of tokens that can
+          // appear after any of the places where AssignmentExpression is used
+          // throughout the grammar.  Conveniently, none of them can also be the
+          // start an expression.
+          case TOK_EOF:
+          case TOK_SEMI:
+          case TOK_RC:
+          case TOK_RB:
+          case TOK_RP:
+          case TOK_COLON:
+          case TOK_COMMA:
+            // No value.
+            exprNode = null();
+            break;
+          case TOK_MUL:
+            kind = PNK_YIELD_STAR;
+            tokenStream.consumeKnownToken(TOK_MUL);
+            // Fall through.
+          default:
+            exprNode = assignExpr();
+            if (!exprNode)
+                return null();
+        }
         return handler.newUnary(kind, JSOP_NOP, begin, exprNode);
       }
 
       case NotGenerator:
         // We are in code that has not seen a yield, but we are in JS 1.7 or
         // later.  Try to transition to being a legacy generator.
         JS_ASSERT(tokenStream.versionNumber() >= JSVERSION_1_7);
         JS_ASSERT(pc->lastYieldOffset == ParseContext<ParseHandler>::NoYieldOffset);
@@ -4880,21 +4904,16 @@ Parser<ParseHandler>::yieldExpression()
           case TOK_SEMI:
           case TOK_RC:
           case TOK_RB:
           case TOK_RP:
           case TOK_COLON:
           case TOK_COMMA:
             // No value.
             exprNode = null();
-            // ES6 does not permit yield without an operand.  We should
-            // encourage users of yield expressions of this kind to pass an
-            // operand, to bring users closer to standard syntax.
-            if (!reportWithOffset(ParseWarning, false, pos().begin, JSMSG_YIELD_WITHOUT_OPERAND))
-                return null();
             break;
           default:
             exprNode = assignExpr();
             if (!exprNode)
                 return null();
         }
 
         return handler.newUnary(PNK_YIELD, JSOP_NOP, begin, exprNode);
--- a/js/src/gc/ForkJoinNursery.cpp
+++ b/js/src/gc/ForkJoinNursery.cpp
@@ -13,17 +13,16 @@
 
 #include "prmjtime.h"
 
 #include "gc/Heap.h"
 #include "jit/IonFrames.h"
 #include "jit/RematerializedFrame.h"
 #include "vm/ArrayObject.h"
 #include "vm/ForkJoin.h"
-#include "vm/TypedArrayObject.h"
 
 #include "jsgcinlines.h"
 #include "gc/Nursery-inl.h"
 #include "vm/ObjectImpl-inl.h"
 
 // The ForkJoinNursery provides an object nursery for movable object
 // types for one ForkJoin worker thread.  There is a one-to-one
 // correspondence between ForkJoinNursery and ForkJoinContext.
@@ -252,17 +251,17 @@ ForkJoinNursery::pjsCollection(int op)
             CrashAtUnhandlableOOM("Cannot expand PJS nursery during GC");
         // newspace must be at least as large as fromSpace
         numActiveChunks_ = currentNumActiveChunks_;
     }
     ForkJoinNurseryCollectionTracer trc(rt, this);
     forwardFromRoots(&trc);
     collectToFixedPoint(&trc);
 #ifdef JS_ION
-    jit::UpdateJitActivationsForMinorGC(TlsPerThreadData.get(), &trc);
+    jit::UpdateJitActivationsForMinorGC<ForkJoinNursery>(TlsPerThreadData.get(), &trc);
 #endif
     freeFromspace();
 
     size_t live = movedSize_;
     computeNurserySizeAfterGC(live, &msg);
 
     sweepHugeSlots();
     JS_ASSERT(hugeSlots[hugeSlotsFrom].empty());
@@ -824,19 +823,16 @@ ForkJoinNursery::copyObjectToTospace(JSO
     // them if there is adequate room inline in dst.
     if (src->is<ArrayObject>())
         srcSize = movedSize = sizeof(ObjectImpl);
 
     js_memcpy(dst, src, srcSize);
     movedSize += copySlotsToTospace(dst, src, dstKind);
     movedSize += copyElementsToTospace(dst, src, dstKind);
 
-    if (src->is<TypedArrayObject>())
-        dst->setPrivate(dst->fixedData(TypedArrayObject::FIXED_DATA_START));
-
     // The shape's list head may point into the old object.
     if (&src->shape_ == dst->shape_->listp) {
         JS_ASSERT(cx_->isThreadLocal(dst->shape_.get()));
         dst->shape_->listp = &dst->shape_;
     }
 
     return movedSize;
 }
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -212,22 +212,32 @@ class GCRuntime
     }
 
     bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; }
     void enterUnsafeRegion() { ++inUnsafeRegion; }
     void leaveUnsafeRegion() {
         JS_ASSERT(inUnsafeRegion > 0);
         --inUnsafeRegion;
     }
+
+    bool isStrictProxyCheckingEnabled() { return disableStrictProxyCheckingCount == 0; }
+    void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; }
+    void enableStrictProxyChecking() {
+        JS_ASSERT(disableStrictProxyCheckingCount > 0);
+        --disableStrictProxyCheckingCount;
+    }
 #endif
 
     void setAlwaysPreserveCode() { alwaysPreserveCode = true; }
 
-    bool isIncrementalGCEnabled() { return incrementalEnabled; }
-    void disableIncrementalGC() { incrementalEnabled = false; }
+    bool isIncrementalGCAllowed() { return incrementalAllowed; }
+    void disallowIncrementalGC() { incrementalAllowed = false; }
+
+    bool isIncrementalGCEnabled() { return mode == JSGC_MODE_INCREMENTAL && incrementalAllowed; }
+    bool isIncrementalGCInProgress() { return state() != gc::NO_INCREMENTAL && !verifyPreData; }
 
     bool isGenerationalGCEnabled() { return generationalDisabled == 0; }
     void disableGenerationalGC();
     void enableGenerationalGC();
 
     void setGrayRootsTracer(JSTraceDataOp traceOp, void *data);
     bool addBlackRootsTracer(JSTraceDataOp traceOp, void *data);
     void removeBlackRootsTracer(JSTraceDataOp traceOp, void *data);
@@ -252,16 +262,43 @@ class GCRuntime
     void incObjectsMarkedInDeadZone() {
         JS_ASSERT(manipulatingDeadZones);
         ++objectsMarkedInDeadZones;
     }
 
     JS::Zone *getCurrentZoneGroup() { return currentZoneGroup; }
     void setFoundBlackGrayEdges() { foundBlackGrayEdges = true; }
 
+    uint64_t gcNumber() { return number; }
+    void incGcNumber() { ++number; }
+
+    bool isIncrementalGc() { return isIncremental; }
+    bool isFullGc() { return isFull; }
+
+    bool shouldCleanUpEverything() { return cleanUpEverything; }
+
+    bool areGrayBitsValid() { return grayBitsValid; }
+    void setGrayBitsInvalid() { grayBitsValid = false; }
+
+    bool isGcNeeded() { return isNeeded; }
+
+    double computeHeapGrowthFactor(size_t lastBytes);
+    size_t computeTriggerBytes(double growthFactor, size_t lastBytes, JSGCInvocationKind gckind);
+    size_t allocationThreshold() { return allocThreshold; }
+
+    JSGCMode gcMode() const { return mode; }
+    void setGCMode(JSGCMode m) {
+        mode = m;
+        marker.setGCMode(mode);
+    }
+
+    inline void updateOnChunkFree(const ChunkInfo &info);
+    inline void updateOnFreeArenaAlloc(const ChunkInfo &info);
+    inline void updateOnArenaFree(const ChunkInfo &info);
+
 #ifdef JS_GC_ZEAL
     void startVerifyPreBarriers();
     bool endVerifyPreBarriers();
     void startVerifyPostBarriers();
     bool endVerifyPostBarriers();
     void finishVerifier();
 #endif
 
@@ -348,102 +385,93 @@ class GCRuntime
     js::gc::Chunk         *userAvailableChunkListHead;
     js::gc::ChunkPool     chunkPool;
 
 #ifdef JSGC_GENERATIONAL
     js::Nursery           nursery;
     js::gc::StoreBuffer   storeBuffer;
 #endif
 
+    js::gcstats::Statistics stats;
+
+    js::GCMarker          marker;
+
     js::RootedValueMap    rootsHash;
 
     /* This is updated by both the main and GC helper threads. */
     mozilla::Atomic<size_t, mozilla::ReleaseAcquire>   bytes;
 
     size_t                maxBytes;
     size_t                maxMallocBytes;
 
+  private:
     /*
      * Number of the committed arenas in all GC chunks including empty chunks.
      */
     mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire>   numArenasFreeCommitted;
-    js::GCMarker          marker;
     void                  *verifyPreData;
     void                  *verifyPostData;
     bool                  chunkAllocationSinceLastGC;
     int64_t               nextFullGCTime;
     int64_t               lastGCTime;
     int64_t               jitReleaseTime;
 
     JSGCMode              mode;
 
-    size_t                allocationThreshold;
+    size_t                allocThreshold;
     bool                  highFrequencyGC;
     uint64_t              highFrequencyTimeThreshold;
     uint64_t              highFrequencyLowLimitBytes;
     uint64_t              highFrequencyHighLimitBytes;
     double                highFrequencyHeapGrowthMax;
     double                highFrequencyHeapGrowthMin;
     double                lowFrequencyHeapGrowth;
     bool                  dynamicHeapGrowth;
     bool                  dynamicMarkSlice;
     uint64_t              decommitThreshold;
 
     /* During shutdown, the GC needs to clean up every possible object. */
-    bool                  shouldCleanUpEverything;
+    bool                  cleanUpEverything;
 
     /*
      * The gray bits can become invalid if UnmarkGray overflows the stack. A
      * full GC will reset this bit, since it fills in all the gray bits.
      */
     bool                  grayBitsValid;
 
     /*
      * These flags must be kept separate so that a thread requesting a
      * compartment GC doesn't cancel another thread's concurrent request for a
      * full GC.
      */
     volatile uintptr_t    isNeeded;
 
-    js::gcstats::Statistics stats;
-
     /* Incremented on every GC slice. */
     uint64_t              number;
 
-    /* The   number at the time of the most recent GC's first slice. */
+    /* The number at the time of the most recent GC's first slice. */
     uint64_t              startNumber;
 
     /* Whether the currently running GC can finish in multiple slices. */
     bool                  isIncremental;
 
     /* Whether all compartments are being collected in first GC slice. */
     bool                  isFull;
 
     /* The reason that an interrupt-triggered GC should be called. */
     JS::gcreason::Reason  triggerReason;
 
     /*
-     * If this is true, all marked objects must belong to a compartment being
-     * GCed. This is used to look for compartment bugs.
-     */
-    bool                  strictCompartmentChecking;
-
-#ifdef DEBUG
-    /*
      * If this is 0, all cross-compartment proxies must be registered in the
      * wrapper map. This checking must be disabled temporarily while creating
      * new wrappers. When non-zero, this records the recursion depth of wrapper
      * creation.
      */
-    uintptr_t             disableStrictProxyCheckingCount;
-#else
-    uintptr_t             unused1;
-#endif
+    mozilla::DebugOnly<uintptr_t>  disableStrictProxyCheckingCount;
 
-  private:
     /*
      * The current incremental GC phase. This is also used internally in
      * non-incremental GC.
      */
     js::gc::State         incrementalState;
 
     /* Indicates that the last incremental slice exhausted the mark stack. */
     bool                  lastMarkSlice;
@@ -488,17 +516,17 @@ class GCRuntime
 
     /* Default budget for incremental GC slice. See SliceBudget in jsgc.h. */
     int64_t               sliceBudget;
 
     /*
      * We disable incremental GC if we encounter a js::Class with a trace hook
      * that does not implement write barriers.
      */
-    bool                  incrementalEnabled;
+    bool                  incrementalAllowed;
 
     /*
      * GGC can be enabled from the command line while testing.
      */
     unsigned              generationalDisabled;
 
     /*
      * This is true if we are in the middle of a brain transplant (e.g.,
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -200,36 +200,38 @@ CheckMarkedThing(JSTracer *trc, T **thin
         return;
 
     JS_ASSERT(thing->zone());
     JS_ASSERT(thing->zone()->runtimeFromMainThread() == trc->runtime());
     JS_ASSERT(trc->hasTracingDetails());
 
     DebugOnly<JSRuntime *> rt = trc->runtime();
 
-    JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gc.isManipulatingDeadZones(),
+    bool isGcMarkingTracer = IS_GC_MARKING_TRACER(trc);
+    JS_ASSERT_IF(isGcMarkingTracer && rt->gc.isManipulatingDeadZones(),
                  !thing->zone()->scheduledForDestruction);
 
     JS_ASSERT(CurrentThreadCanAccessRuntime(rt));
 
-    JS_ASSERT_IF(thing->zone()->requireGCTracer(),
-                 IS_GC_MARKING_TRACER(trc));
+    JS_ASSERT_IF(thing->zone()->requireGCTracer(), isGcMarkingTracer);
 
     JS_ASSERT(thing->isAligned());
 
     JS_ASSERT(MapTypeToTraceKind<T>::kind == GetGCThingTraceKind(thing));
 
-    JS_ASSERT_IF(rt->gc.strictCompartmentChecking,
-                 thing->zone()->isCollecting() || rt->isAtomsZone(thing->zone()));
+    if (isGcMarkingTracer) {
+        GCMarker *gcMarker = static_cast<GCMarker *>(trc);
+        JS_ASSERT_IF(gcMarker->shouldCheckCompartments(),
+                     thing->zone()->isCollecting() || rt->isAtomsZone(thing->zone()));
 
-    JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && AsGCMarker(trc)->getMarkColor() == GRAY,
-                 !thing->zone()->isGCMarkingBlack() || rt->isAtomsZone(thing->zone()));
+        JS_ASSERT_IF(gcMarker->getMarkColor() == GRAY,
+                     !thing->zone()->isGCMarkingBlack() || rt->isAtomsZone(thing->zone()));
 
-    JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc),
-                 !(thing->zone()->isGCSweeping() || thing->zone()->isGCFinished()));
+        JS_ASSERT(!(thing->zone()->isGCSweeping() || thing->zone()->isGCFinished()));
+    }
 
     /*
      * Try to assert that the thing is allocated.  This is complicated by the
      * fact that allocated things may still contain the poison pattern if that
      * part has not been overwritten, and that the free span list head in the
      * ArenaHeader may not be synced with the real one in ArenaLists.
      */
     JS_ASSERT_IF(IsThingPoisoned(thing) && rt->isHeapBusy(),
@@ -409,19 +411,19 @@ IsMarked(T **thingp)
     JS_ASSERT(*thingp);
 #ifdef JSGC_GENERATIONAL
     JSRuntime* rt = (*thingp)->runtimeFromAnyThread();
 #ifdef JSGC_FJGENERATIONAL
     // Must precede the case for JSGC_GENERATIONAL because IsInsideNursery()
     // will also be true for the ForkJoinNursery.
     if (rt->isFJMinorCollecting()) {
         ForkJoinContext *ctx = ForkJoinContext::current();
-        ForkJoinNursery &fjNursery = ctx->fjNursery();
-        if (fjNursery.isInsideFromspace(*thingp))
-            return fjNursery.getForwardedPointer(thingp);
+        ForkJoinNursery &nursery = ctx->nursery();
+        if (nursery.isInsideFromspace(*thingp))
+            return nursery.getForwardedPointer(thingp);
     }
     else
 #endif
     {
         if (IsInsideNursery(*thingp)) {
             Nursery &nursery = rt->gc.nursery;
             return nursery.getForwardedPointer(thingp);
         }
@@ -446,19 +448,19 @@ IsAboutToBeFinalized(T **thingp)
     /* Permanent atoms are never finalized by non-owning runtimes. */
     if (ThingIsPermanentAtom(thing) && !TlsPerThreadData.get()->associatedWith(rt))
         return false;
 
 #ifdef JSGC_GENERATIONAL
 #ifdef JSGC_FJGENERATIONAL
     if (rt->isFJMinorCollecting()) {
         ForkJoinContext *ctx = ForkJoinContext::current();
-        ForkJoinNursery &fjNursery = ctx->fjNursery();
-        if (fjNursery.isInsideFromspace(thing))
-            return !fjNursery.getForwardedPointer(thingp);
+        ForkJoinNursery &nursery = ctx->nursery();
+        if (nursery.isInsideFromspace(thing))
+            return !nursery.getForwardedPointer(thingp);
     }
     else
 #endif
     {
         Nursery &nursery = rt->gc.nursery;
         JS_ASSERT_IF(!rt->isHeapMinorCollecting(), !IsInsideNursery(thing));
         if (rt->isHeapMinorCollecting()) {
             if (IsInsideNursery(thing))
@@ -487,19 +489,19 @@ template <typename T>
 T *
 UpdateIfRelocated(JSRuntime *rt, T **thingp)
 {
     JS_ASSERT(thingp);
 #ifdef JSGC_GENERATIONAL
 #ifdef JSGC_FJGENERATIONAL
     if (*thingp && rt->isFJMinorCollecting()) {
         ForkJoinContext *ctx = ForkJoinContext::current();
-        ForkJoinNursery &fjNursery = ctx->fjNursery();
-        if (fjNursery.isInsideFromspace(*thingp))
-            fjNursery.getForwardedPointer(thingp);
+        ForkJoinNursery &nursery = ctx->nursery();
+        if (nursery.isInsideFromspace(*thingp))
+            nursery.getForwardedPointer(thingp);
     }
     else
 #endif
     {
         if (*thingp && rt->isHeapMinorCollecting() && IsInsideNursery(*thingp))
             rt->gc.nursery.getForwardedPointer(thingp);
     }
 #endif  // JSGC_GENERATIONAL
@@ -1686,18 +1688,17 @@ GCMarker::processMarkStackTop(SliceBudge
         PushMarkStack(this, shape);
 
         /* Call the trace hook if necessary. */
         const Class *clasp = type->clasp();
         if (clasp->trace) {
             // Global objects all have the same trace hook. That hook is safe without barriers
             // if the gloal has no custom trace hook of it's own, or has been moved to a different
             // compartment, and so can't have one.
-            JS_ASSERT_IF(runtime()->gcMode() == JSGC_MODE_INCREMENTAL &&
-                         runtime()->gc.isIncrementalGCEnabled() &&
+            JS_ASSERT_IF(runtime()->gc.isIncrementalGCEnabled() &&
                          !(clasp->trace == JS_GlobalObjectTraceHook &&
                            (!obj->compartment()->options().getTrace() ||
                             !obj->isOwnGlobal())),
                          clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
             clasp->trace(this, obj);
         }
 
         if (!shape->isNative())
@@ -1728,26 +1729,24 @@ GCMarker::processMarkStackTop(SliceBudge
         goto scan_value_array;
     }
 }
 
 bool
 GCMarker::drainMarkStack(SliceBudget &budget)
 {
 #ifdef DEBUG
-    JSRuntime *rt = runtime();
-
     struct AutoCheckCompartment {
-        JSRuntime *runtime;
-        explicit AutoCheckCompartment(JSRuntime *rt) : runtime(rt) {
-            JS_ASSERT(!rt->gc.strictCompartmentChecking);
-            runtime->gc.strictCompartmentChecking = true;
+        bool &flag;
+        explicit AutoCheckCompartment(bool &comparmentCheckFlag) : flag(comparmentCheckFlag) {
+            JS_ASSERT(!flag);
+            flag = true;
         }
-        ~AutoCheckCompartment() { runtime->gc.strictCompartmentChecking = false; }
-    } acc(rt);
+        ~AutoCheckCompartment() { flag = false; }
+    } acc(strictCompartmentChecking);
 #endif
 
     if (budget.isOverBudget())
         return false;
 
     for (;;) {
         while (!stack.isEmpty()) {
             processMarkStackTop(budget);
@@ -1890,17 +1889,17 @@ UnmarkGrayChildren(JSTracer *trc, void *
 {
     void *thing = *thingp;
     int stackDummy;
     if (!JS_CHECK_STACK_SIZE(trc->runtime()->mainThread.nativeStackLimit[StackForSystemCode], &stackDummy)) {
         /*
          * If we run out of stack, we take a more drastic measure: require that
          * we GC again before the next CC.
          */
-        trc->runtime()->gc.grayBitsValid = false;
+        trc->runtime()->gc.setGrayBitsInvalid();
         return;
     }
 
     UnmarkGrayTracer *tracer = static_cast<UnmarkGrayTracer *>(trc);
     if (!IsInsideNursery(static_cast<Cell *>(thing))) {
         if (!JS::GCThingIsMarkedGray(thing))
             return;
 
--- a/js/src/gc/Nursery-inl.h
+++ b/js/src/gc/Nursery-inl.h
@@ -8,16 +8,18 @@
 #ifndef gc_Nursery_inl_h
 #define gc_Nursery_inl_h
 
 #ifdef JSGC_GENERATIONAL
 
 #include "gc/Nursery.h"
 
 #include "gc/Heap.h"
+#include "js/TracingAPI.h"
+#include "vm/Runtime.h"
 
 namespace js {
 namespace gc {
 
 /* static */
 inline RelocationOverlay *
 RelocationOverlay::fromCell(Cell *cell)
 {
@@ -65,11 +67,17 @@ js::Nursery::getForwardedPointer(T **ref
     const gc::RelocationOverlay *overlay = reinterpret_cast<const gc::RelocationOverlay *>(*ref);
     if (!overlay->isForwarded())
         return false;
     /* This static cast from Cell* restricts T to valid (GC thing) types. */
     *ref = static_cast<T *>(overlay->forwardingAddress());
     return true;
 }
 
+inline void
+js::Nursery::forwardBufferPointer(JSTracer* trc, HeapSlot **pSlotElems)
+{
+    trc->runtime()->gc.nursery.forwardBufferPointer(pSlotElems);
+}
+
 #endif /* JSGC_GENERATIONAL */
 
 #endif /* gc_Nursery_inl_h */
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -29,17 +29,20 @@
 #include "vm/TypedArrayObject.h"
 
 #include "jsgcinlines.h"
 
 #include "vm/ObjectImpl-inl.h"
 
 using namespace js;
 using namespace gc;
-using namespace mozilla;
+
+using mozilla::ArrayLength;
+using mozilla::PodCopy;
+using mozilla::PodZero;
 
 //#define PROFILE_NURSERY
 
 #ifdef PROFILE_NURSERY
 /*
  * Print timing information for minor GCs that take longer than this time in microseconds.
  */
 static int64_t GCReportThreshold = INT64_MAX;
@@ -328,17 +331,17 @@ class MinorCollectionTracer : public JST
         nursery(nursery),
         session(rt, MinorCollecting),
         tenuredSize(0),
         head(nullptr),
         tail(&head),
         savedRuntimeNeedBarrier(rt->needsBarrier()),
         disableStrictProxyChecking(rt)
     {
-        rt->gc.number++;
+        rt->gc.incGcNumber();
 
         /*
          * We disable the runtime needsBarrier() check so that pre-barriers do
          * not fire on objects that have been relocated. The pre-barrier's
          * call to obj->zone() will try to look through shape_, which is now
          * the relocation magic and will crash. However, zone->needsBarrier()
          * must still be set correctly so that allocations we make in minor
          * GCs between incremental slices will allocate their objects marked.
@@ -828,17 +831,17 @@ js::Nursery::collect(JSRuntime *rt, JS::
         if (!c->gcLiveArrayBuffers.empty())
             ArrayBufferObject::sweep(c);
     }
     TIME_END(sweepArrayBufferViewList);
 
     // Update any slot or element pointers whose destination has been tenured.
     TIME_START(updateJitActivations);
 #ifdef JS_ION
-    js::jit::UpdateJitActivationsForMinorGC(rt, &trc);
+    js::jit::UpdateJitActivationsForMinorGC<Nursery>(&rt->mainThread, &trc);
 #endif
     TIME_END(updateJitActivations);
 
     // Resize the nursery.
     TIME_START(resize);
     double promotionRate = trc.tenuredSize / double(allocationEnd() - start());
     if (promotionRate > 0.05)
         growAllocableSpace();
--- a/js/src/gc/Nursery.h
+++ b/js/src/gc/Nursery.h
@@ -159,16 +159,18 @@ class Nursery
      * returns false and leaves |*ref| unset.
      */
     template <typename T>
     MOZ_ALWAYS_INLINE bool getForwardedPointer(T **ref);
 
     /* Forward a slots/elements pointer stored in an Ion frame. */
     void forwardBufferPointer(HeapSlot **pSlotsElems);
 
+    static void forwardBufferPointer(JSTracer* trc, HeapSlot **pSlotsElems);
+
     size_t sizeOfHeapCommitted() const {
         return numActiveChunks_ * gc::ChunkSize;
     }
     size_t sizeOfHeapDecommitted() const {
         return (NumNurseryChunks - numActiveChunks_) * gc::ChunkSize;
     }
     size_t sizeOfHugeSlots(mozilla::MallocSizeOf mallocSizeOf) const {
         size_t total = 0;
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -552,17 +552,17 @@ Statistics::endGC()
         (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, collectedCount == zoneCount ? 0 : 1);
         (*cb)(JS_TELEMETRY_GC_MS, t(total));
         (*cb)(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
         (*cb)(JS_TELEMETRY_GC_MARK_MS, t(phaseTimes[PHASE_MARK]));
         (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(phaseTimes[PHASE_SWEEP]));
         (*cb)(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(phaseTimes[PHASE_MARK_ROOTS]));
         (*cb)(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_SWEEP_MARK_GRAY]));
         (*cb)(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason);
-        (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCEnabled());
+        (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.isIncrementalGCAllowed());
         (*cb)(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal));
         (*cb)(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest));
 
         double mmu50 = computeMMU(50 * PRMJ_USEC_PER_MSEC);
         (*cb)(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
     }
 
     if (fp)
--- a/js/src/gc/Tracer.cpp
+++ b/js/src/gc/Tracer.cpp
@@ -457,17 +457,18 @@ MarkStack::sizeOfExcludingThis(mozilla::
  */
 GCMarker::GCMarker(JSRuntime *rt)
   : JSTracer(rt, nullptr, DoNotTraceWeakMaps),
     stack(size_t(-1)),
     color(BLACK),
     unmarkedArenaStackTop(nullptr),
     markLaterArenas(0),
     grayBufferState(GRAY_BUFFER_UNUSED),
-    started(false)
+    started(false),
+    strictCompartmentChecking(false)
 {
 }
 
 bool
 GCMarker::init(JSGCMode gcMode)
 {
     return stack.init(gcMode);
 }
@@ -685,13 +686,11 @@ GCMarker::sizeOfExcludingThis(mozilla::M
     for (ZonesIter zone(runtime(), WithAtoms); !zone.done(); zone.next())
         size += zone->gcGrayRoots.sizeOfExcludingThis(mallocSizeOf);
     return size;
 }
 
 void
 js::SetMarkStackLimit(JSRuntime *rt, size_t limit)
 {
-    JS_ASSERT(!rt->isHeapBusy());
-    AutoStopVerifyingBarriers pauseVerification(rt, false);
-    rt->gc.marker.setMaxCapacity(limit);
+    rt->gc.setMarkStackLimit(limit);
 }
 
--- a/js/src/gc/Tracer.h
+++ b/js/src/gc/Tracer.h
@@ -204,16 +204,20 @@ class GCMarker : public JSTracer
     void markBufferedGrayRoots(JS::Zone *zone);
 
     static void GrayCallback(JSTracer *trc, void **thing, JSGCTraceKind kind);
 
     void setGCMode(JSGCMode mode) { stack.setGCMode(mode); }
 
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
+#ifdef DEBUG
+    bool shouldCheckCompartments() { return strictCompartmentChecking; }
+#endif
+
     /* This is public exclusively for ScanRope. */
     MarkStack stack;
 
   private:
 #ifdef DEBUG
     void checkZone(void *p);
 #else
     void checkZone(void *p) {}
@@ -286,16 +290,22 @@ class GCMarker : public JSTracer
         GRAY_BUFFER_UNUSED,
         GRAY_BUFFER_OK,
         GRAY_BUFFER_FAILED
     };
     GrayBufferState grayBufferState;
 
     /* Assert that start and stop are called with correct ordering. */
     mozilla::DebugOnly<bool> started;
+
+    /*
+     * If this is true, all marked objects must belong to a compartment being
+     * GCed. This is used to look for compartment bugs.
+     */
+    mozilla::DebugOnly<bool> strictCompartmentChecking;
 };
 
 void
 SetMarkStackLimit(JSRuntime *rt, size_t limit);
 
 } /* namespace js */
 
 /*
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -17,17 +17,16 @@
 #include "js/GCAPI.h"
 #include "js/HashTable.h"
 
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 
 using namespace js;
 using namespace js::gc;
-using namespace mozilla;
 
 #ifdef JS_GC_ZEAL
 
 /*
  * Write barrier verification
  *
  * The next few functions are for write barrier verification.
  *
@@ -98,17 +97,17 @@ struct VerifyPreTracer : JSTracer
     /* This graph represents the initial GC "snapshot". */
     VerifyNode *curnode;
     VerifyNode *root;
     char *edgeptr;
     char *term;
     NodeMap nodemap;
 
     VerifyPreTracer(JSRuntime *rt, JSTraceCallback callback)
-      : JSTracer(rt, callback), noggc(rt), number(rt->gc.number), count(0), root(nullptr)
+      : JSTracer(rt, callback), noggc(rt), number(rt->gc.gcNumber()), count(0), root(nullptr)
     {}
 
     ~VerifyPreTracer() {
         js_free(root);
     }
 };
 
 /*
@@ -385,17 +384,17 @@ struct VerifyPostTracer : JSTracer
     /* This counts up to gcZealFrequency to decide whether to verify. */
     int count;
 
     /* The set of edges in the StoreBuffer at the end of verification. */
     typedef HashSet<void **, PointerHasher<void **, 3>, SystemAllocPolicy> EdgeSet;
     EdgeSet *edges;
 
     VerifyPostTracer(JSRuntime *rt, JSTraceCallback callback)
-      : JSTracer(rt, callback), number(rt->gc.number), count(0)
+      : JSTracer(rt, callback), number(rt->gc.gcNumber()), count(0)
     {}
 };
 
 /*
  * The post-barrier verifier runs the full store buffer and a fake nursery when
  * running and when it stops, walks the full heap to ensure that all the
  * important edges were inserted into the storebuffer.
  */
--- a/js/src/gc/Zone.cpp
+++ b/js/src/gc/Zone.cpp
@@ -218,17 +218,17 @@ Zone::discardJitCode(FreeOp *fop)
 #endif
 }
 
 uint64_t
 Zone::gcNumber()
 {
     // Zones in use by exclusive threads are not collected, and threads using
     // them cannot access the main runtime's gcNumber without racing.
-    return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gc.number;
+    return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gc.gcNumber();
 }
 
 #ifdef JS_ION
 js::jit::JitZone *
 Zone::createJitZone(JSContext *cx)
 {
     MOZ_ASSERT(!jitZone_);
 
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -1474,17 +1474,17 @@ class irregexp::RegExpCompiler
 
     LifoAlloc *alloc() const { return alloc_; }
 
     static const int kNoRegister = -1;
 
   private:
     EndNode* accept_;
     int next_register_;
-    js::Vector<RegExpNode *, 4, SystemAllocPolicy> work_list_;
+    Vector<RegExpNode *, 4, SystemAllocPolicy> work_list_;
     int recursion_depth_;
     RegExpMacroAssembler* macro_assembler_;
     bool ignore_case_;
     bool ascii_;
     bool reg_exp_too_big_;
     int current_expansion_factor_;
     FrequencyCollator frequency_collator_;
     LifoAlloc *alloc_;
@@ -2967,17 +2967,17 @@ EmitDoubleBoundaryTest(RegExpMacroAssemb
             masm->CheckCharacter(first, in_range);
         else
             masm->CheckCharacterInRange(first, last, in_range);
         if (out_of_range != fall_through)
             masm->JumpOrBacktrack(out_of_range);
     }
 }
 
-typedef js::Vector<int, 4, LifoAllocPolicy<Infallible> > RangeBoundaryVector;
+typedef Vector<int, 4, LifoAllocPolicy<Infallible> > RangeBoundaryVector;
 
 // even_label is for ranges[i] to ranges[i + 1] where i - start_index is even.
 // odd_label is for ranges[i] to ranges[i + 1] where i - start_index is odd.
 static void
 EmitUseLookupTable(RegExpMacroAssembler* masm,
                    RangeBoundaryVector &ranges,
                    int start_index,
                    int end_index,
@@ -3969,17 +3969,17 @@ class AlternativeGenerationList
     }
 
     AlternativeGeneration *at(int i) {
         return alt_gens_[i];
     }
 
   private:
     static const size_t kAFew = 10;
-    js::Vector<AlternativeGeneration *, 1, LifoAllocPolicy<Infallible> > alt_gens_;
+    Vector<AlternativeGeneration *, 1, LifoAllocPolicy<Infallible> > alt_gens_;
     AlternativeGeneration a_few_alt_gens_[kAFew];
 };
 
 void
 ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
 {
     RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
     size_t choice_count = alternatives().length();
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -324,17 +324,26 @@ function rround_number(i) {
 }
 
 var uceFault_round_double = eval(uneval(uceFault).replace('uceFault', 'uceFault_round_double'));
 function rround_double(i) {
     var x = Math.round(i + (-1 >>> 0));
     if (uceFault_round_double(i) || uceFault_round_double(i))
         assertEq(x, 99 + (-1 >>> 0)); /* = i + 2 ^ 32 - 1 */
      return i;
- }
+}
+
+var uceFault_Char_Code_At = eval(uneval(uceFault).replace('uceFault', 'uceFault_Char_Code_At'));
+function rcharCodeAt(i) {
+    var s = "aaaaa";
+    var x = s.charCodeAt(i % 4);
+    if (uceFault_Char_Code_At(i) || uceFault_Char_Code_At(i))
+        assertEq(x, 97 );
+    return i;
+}
 
 var uceFault_from_char_code = eval(uneval(uceFault).replace('uceFault', 'uceFault_from_char_code'));
 function rfrom_char_code(i) {
     var x = String.fromCharCode(i);
     if (uceFault_from_char_code(i) || uceFault_from_char_code(i))
         assertEq(x, "c");
     return i;
 }
@@ -415,16 +424,17 @@ for (i = 0; i < 100; i++) {
     rmod_number(i);
     rmod_object(i);
     rconcat_string(i);
     rconcat_number(i);
     rfloor_number(i);
     rfloor_object(i);
     rround_number(i);
     rround_double(i);
+    rcharCodeAt(i);
     rfrom_char_code(i);
     rfrom_char_code_non_ascii(i);
     rpow_number(i);
     rpow_object(i);
     rpowhalf_number(i);
     rpowhalf_object(i);
 }
 
--- a/js/src/jit-test/tests/parser/yield-without-operand.js
+++ b/js/src/jit-test/tests/parser/yield-without-operand.js
@@ -1,22 +1,20 @@
-// yield without an operand causes a warning. See bug 885463.
+// yield without an operand is fine and dandy.
 
 load(libdir + "asserts.js");
 
-assertWarning(() => Function("yield"), SyntaxError,
-             "yield followed by EOF should cause a warning");
-assertWarning(() => Function("yield;"), SyntaxError,
-             "yield followed by semicolon should cause a warning");
-assertWarning(() => Function("yield\n  print('ok');"), SyntaxError,
-             "yield followed by newline should cause a warning");
+assertNoWarning(() => Function("yield"), SyntaxError,
+                "yield followed by EOF is fine");
+assertNoWarning(() => Function("yield;"), SyntaxError,
+                "yield followed by semicolon is fine");
+assertNoWarning(() => Function("yield\n  print('ok');"), SyntaxError,
+                "yield followed by newline is fine");
 
-assertWarning(() => eval("(function () { yield; })"), SyntaxError,
-             "yield followed by semicolon in eval code should cause a warning");
-assertWarning(() => eval("(function () { yield })"), SyntaxError,
-             "yield followed by } in eval code should cause a warning");
+assertNoWarning(() => eval("(function () { yield; })"), SyntaxError,
+                "yield followed by semicolon in eval code is fine");
+assertNoWarning(() => eval("(function () { yield })"), SyntaxError,
+                "yield followed by } in eval code is fine");
 
 assertNoWarning(() => Function("yield 0;"),
                 "yield with an operand should be fine");
 assertNoWarning(() => Function("yield 0"),
                 "yield with an operand should be fine, even without a semicolon");
-
-print("\npassed - all those warnings are normal and there's no real way to suppress them");
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -654,20 +654,20 @@ class ABIArgIter
     ABIArg *operator->() { JS_ASSERT(!done()); return &gen_.current(); }
     ABIArg &operator*() { JS_ASSERT(!done()); return gen_.current(); }
 
     unsigned index() const { JS_ASSERT(!done()); return i_; }
     MIRType mirType() const { JS_ASSERT(!done()); return ToMIRType(types_[i_]); }
     uint32_t stackBytesConsumedSoFar() const { return gen_.stackBytesConsumedSoFar(); }
 };
 
-typedef js::Vector<MIRType, 8> MIRTypeVector;
+typedef Vector<MIRType, 8> MIRTypeVector;
 typedef ABIArgIter<MIRTypeVector> ABIArgMIRTypeIter;
 
-typedef js::Vector<VarType, 8, LifoAllocPolicy<Fallible> > VarTypeVector;
+typedef Vector<VarType, 8, LifoAllocPolicy<Fallible> > VarTypeVector;
 typedef ABIArgIter<VarTypeVector> ABIArgTypeIter;
 
 class Signature
 {
     VarTypeVector argTypes_;
     RetType retType_;
 
   public:
@@ -744,18 +744,18 @@ TypedArrayLoadType(ArrayBufferView::View
 
 enum NeedsBoundsCheck {
     NO_BOUNDS_CHECK,
     NEEDS_BOUNDS_CHECK
 };
 
 namespace {
 
-typedef js::Vector<PropertyName*,1> LabelVector;
-typedef js::Vector<MBasicBlock*,8> BlockVector;
+typedef Vector<PropertyName*,1> LabelVector;
+typedef Vector<MBasicBlock*,8> BlockVector;
 
 // ModuleCompiler encapsulates the compilation of an entire asm.js module. Over
 // the course of an ModuleCompiler object's lifetime, many FunctionCompiler
 // objects will be created and destroyed in sequence, one for each function in
 // the module.
 //
 // *** asm.js FFI calls ***
 //
@@ -924,17 +924,17 @@ class MOZ_STACK_CLASS ModuleCompiler
             return u.viewType_;
         }
         AsmJSMathBuiltinFunction mathBuiltinFunction() const {
             JS_ASSERT(which_ == MathBuiltinFunction);
             return u.mathBuiltinFunc_;
         }
     };
 
-    typedef js::Vector<const Func*> FuncPtrVector;
+    typedef Vector<const Func*> FuncPtrVector;
 
     class FuncPtrTable
     {
         Signature sig_;
         uint32_t mask_;
         uint32_t globalDataOffset_;
         FuncPtrVector elems_;
 
@@ -954,17 +954,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         unsigned globalDataOffset() const { return globalDataOffset_; }
 
         bool initialized() const { return !elems_.empty(); }
         void initElems(FuncPtrVector &&elems) { elems_ = Move(elems); JS_ASSERT(initialized()); }
         unsigned numElems() const { JS_ASSERT(initialized()); return elems_.length(); }
         const Func &elem(unsigned i) const { return *elems_[i]; }
     };
 
-    typedef js::Vector<FuncPtrTable> FuncPtrTableVector;
+    typedef Vector<FuncPtrTable> FuncPtrTableVector;
 
     class ExitDescriptor
     {
         PropertyName *name_;
         Signature sig_;
 
       public:
         ExitDescriptor(PropertyName *name, Signature &&sig)
@@ -1017,19 +1017,19 @@ class MOZ_STACK_CLASS ModuleCompiler
         PropertyName *name;
         unsigned ms;
         unsigned line;
         unsigned column;
     };
 
     typedef HashMap<PropertyName*, MathBuiltin> MathNameMap;
     typedef HashMap<PropertyName*, Global*> GlobalMap;
-    typedef js::Vector<Func*> FuncVector;
-    typedef js::Vector<AsmJSGlobalAccess> GlobalAccessVector;
-    typedef js::Vector<SlowFunction> SlowFunctionVector;
+    typedef Vector<Func*> FuncVector;
+    typedef Vector<AsmJSGlobalAccess> GlobalAccessVector;
+    typedef Vector<SlowFunction> SlowFunctionVector;
 
     ExclusiveContext *             cx_;
     AsmJSParser &                  parser_;
 
     MacroAssembler                 masm_;
 
     ScopedJSDeletePtr<AsmJSModule> module_;
     LifoAlloc                      moduleLifo_;
@@ -1795,20 +1795,20 @@ class FunctionCompiler
     {
         VarType type;
         Value value;
         TypedValue(VarType t, const Value &v) : type(t), value(v) {}
     };
 
   private:
     typedef HashMap<PropertyName*, Local> LocalMap;
-    typedef js::Vector<TypedValue> VarInitializerVector;
+    typedef Vector<TypedValue> VarInitializerVector;
     typedef HashMap<PropertyName*, BlockVector> LabeledBlockMap;
     typedef HashMap<ParseNode*, BlockVector> UnlabeledBlockMap;
-    typedef js::Vector<ParseNode*, 4> NodeStack;
+    typedef Vector<ParseNode*, 4> NodeStack;
 
     ModuleCompiler &       m_;
     LifoAlloc &            lifo_;
     ParseNode *            fn_;
     uint32_t               functionNameIndex_;
 
     LocalMap               locals_;
     VarInitializerVector   varInitializers_;
@@ -2189,17 +2189,17 @@ class FunctionCompiler
     {
         ParseNode *node_;
         ABIArgGenerator abi_;
         uint32_t prevMaxStackBytes_;
         uint32_t maxChildStackBytes_;
         uint32_t spIncrement_;
         Signature sig_;
         MAsmJSCall::Args regArgs_;
-        js::Vector<MAsmJSPassStackArg*> stackArgs_;
+        Vector<MAsmJSPassStackArg*> stackArgs_;
         bool childClobbers_;
 
         friend class FunctionCompiler;
 
       public:
         Call(FunctionCompiler &f, ParseNode *callNode, RetType retType)
           : node_(callNode),
             prevMaxStackBytes_(0),
@@ -5355,17 +5355,17 @@ CheckFunction(ModuleCompiler &m, LifoAll
     func->define(m, fn);
     func->accumulateCompileTime((PRMJ_Now() - before) / PRMJ_USEC_PER_MSEC);
 
     m.parser().release(mark);
 
     // Copy the cumulative minimum heap size constraint to the MIR for use in analysis.  The length
     // is also constrained to particular lengths, so firstly round up - a larger 'heap required
     // length' can help range analysis to prove that bounds checks are not needed.
-    uint32_t len = js::RoundUpToNextValidAsmJSHeapLength(m.minHeapLength());
+    uint32_t len = RoundUpToNextValidAsmJSHeapLength(m.minHeapLength());
     m.requireHeapLengthToBeAtLeast(len);
 
     *mir = f.extractMIR();
     (*mir)->noteMinAsmJSHeapLength(len);
     *funcOut = func;
     return true;
 }
 
@@ -5488,21 +5488,21 @@ ParallelCompilationEnabled(ExclusiveCont
     if (!cx->isJSContext())
         return true;
     return cx->asJSContext()->runtime()->canUseOffthreadIonCompilation();
 }
 
 // State of compilation as tracked and updated by the main thread.
 struct ParallelGroupState
 {
-    js::Vector<AsmJSParallelTask> &tasks;
+    Vector<AsmJSParallelTask> &tasks;
     int32_t outstandingJobs; // Good work, jobs!
     uint32_t compiledJobs;
 
-    explicit ParallelGroupState(js::Vector<AsmJSParallelTask> &tasks)
+    explicit ParallelGroupState(Vector<AsmJSParallelTask> &tasks)
       : tasks(tasks), outstandingJobs(0), compiledJobs(0)
     { }
 };
 
 // Block until a helper-assigned LifoAlloc becomes finished.
 static AsmJSParallelTask *
 GetFinishedCompilation(ModuleCompiler &m, ParallelGroupState &group)
 {
@@ -5672,17 +5672,17 @@ CheckFunctionsParallel(ModuleCompiler &m
 
     IonSpew(IonSpew_Logs, "Can't log asm.js script. (Compiled on background thread.)");
 
     // Saturate all helper threads plus the main thread.
     size_t numParallelJobs = HelperThreadState().threadCount + 1;
 
     // Allocate scoped AsmJSParallelTask objects. Each contains a unique
     // LifoAlloc that provides all necessary memory for compilation.
-    js::Vector<AsmJSParallelTask, 0> tasks(m.cx());
+    Vector<AsmJSParallelTask, 0> tasks(m.cx());
     if (!tasks.initCapacity(numParallelJobs))
         return false;
 
     for (size_t i = 0; i < numParallelJobs; i++)
         tasks.infallibleAppend(LIFO_ALLOC_PARALLEL_CHUNK_SIZE);
 
     // With compilation memory in-scope, dispatch helper threads.
     ParallelGroupState group(tasks);
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -760,17 +760,17 @@ AsmJSModule::Name::serialize(uint8_t *cu
 {
     return SerializeName(cursor, name_);
 }
 
 template <typename CharT>
 static const uint8_t *
 DeserializeChars(ExclusiveContext *cx, const uint8_t *cursor, size_t length, PropertyName **name)
 {
-    js::Vector<CharT> tmp(cx);
+    Vector<CharT> tmp(cx);
     CharT *src;
     if ((size_t(cursor) & (sizeof(CharT) - 1)) != 0) {
         // Align 'src' for AtomizeChars.
         if (!tmp.resize(length))
             return nullptr;
         memcpy(tmp.begin(), cursor, length * sizeof(CharT));
         src = tmp.begin();
     } else {
@@ -813,37 +813,37 @@ bool
 AsmJSModule::Name::clone(ExclusiveContext *cx, Name *out) const
 {
     out->name_ = name_;
     return true;
 }
 
 template <class T>
 size_t
-SerializedVectorSize(const js::Vector<T, 0, SystemAllocPolicy> &vec)
+SerializedVectorSize(const Vector<T, 0, SystemAllocPolicy> &vec)
 {
     size_t size = sizeof(uint32_t);
     for (size_t i = 0; i < vec.length(); i++)
         size += vec[i].serializedSize();
     return size;
 }
 
 template <class T>
 uint8_t *
-SerializeVector(uint8_t *cursor, const js::Vector<T, 0, SystemAllocPolicy> &vec)
+SerializeVector(uint8_t *cursor, const Vector<T, 0, SystemAllocPolicy> &vec)
 {
     cursor = WriteScalar<uint32_t>(cursor, vec.length());
     for (size_t i = 0; i < vec.length(); i++)
         cursor = vec[i].serialize(cursor);
     return cursor;
 }
 
 template <class T>
 const uint8_t *
-DeserializeVector(ExclusiveContext *cx, const uint8_t *cursor, js::Vector<T, 0, SystemAllocPolicy> *vec)
+DeserializeVector(ExclusiveContext *cx, const uint8_t *cursor, Vector<T, 0, SystemAllocPolicy> *vec)
 {
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
     if (!vec->resize(length))
         return nullptr;
     for (size_t i = 0; i < vec->length(); i++) {
         if (!(cursor = (*vec)[i].deserialize(cx, cursor)))
             return nullptr;
@@ -1365,33 +1365,33 @@ struct PropertyNameWrapper
         return DeserializeName(cx, cursor, &name);
     }
 };
 
 class ModuleChars
 {
   protected:
     uint32_t isFunCtor_;
-    js::Vector<PropertyNameWrapper, 0, SystemAllocPolicy> funCtorArgs_;
+    Vector<PropertyNameWrapper, 0, SystemAllocPolicy> funCtorArgs_;
 
   public:
     static uint32_t beginOffset(AsmJSParser &parser) {
       return parser.pc->maybeFunction->pn_pos.begin;
     }
 
     static uint32_t endOffset(AsmJSParser &parser) {
       return parser.tokenStream.peekTokenPos().end;
     }
 };
 
 class ModuleCharsForStore : ModuleChars
 {
     uint32_t uncompressedSize_;
     uint32_t compressedSize_;
-    js::Vector<char, 0, SystemAllocPolicy> compressedBuffer_;
+    Vector<char, 0, SystemAllocPolicy> compressedBuffer_;
 
   public:
     bool init(AsmJSParser &parser) {
         JS_ASSERT(beginOffset(parser) < endOffset(parser));
 
         uncompressedSize_ = (endOffset(parser) - beginOffset(parser)) * sizeof(jschar);
         size_t maxCompressedSize = LZ4::maxCompressedSize(uncompressedSize_);
         if (maxCompressedSize < uncompressedSize_)
@@ -1449,17 +1449,17 @@ class ModuleCharsForStore : ModuleChars
         if (isFunCtor_)
             cursor = SerializeVector(cursor, funCtorArgs_);
         return cursor;
     }
 };
 
 class ModuleCharsForLookup : ModuleChars
 {
-    js::Vector<jschar, 0, SystemAllocPolicy> chars_;
+    Vector<jschar, 0, SystemAllocPolicy> chars_;
 
   public:
     const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor) {
         uint32_t uncompressedSize;
         cursor = ReadScalar<uint32_t>(cursor, &uncompressedSize);
 
         uint32_t compressedSize;
         cursor = ReadScalar<uint32_t>(cursor, &compressedSize);
--- a/js/src/jit/AsmJSSignalHandlers.cpp
+++ b/js/src/jit/AsmJSSignalHandlers.cpp
@@ -1,24 +1,27 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/AsmJSSignalHandlers.h"
 
+#include "mozilla/DebugOnly.h"
+
 #include "assembler/assembler/MacroAssembler.h"
 #include "jit/AsmJSModule.h"
+#include "vm/Runtime.h"
 
 using namespace js;
 using namespace js::jit;
-using namespace mozilla;
 
 using JS::GenericNaN;
+using mozilla::DebugOnly;
 
 #if defined(XP_WIN)
 # define XMM_sig(p,i) ((p)->Xmm##i)
 # define EIP_sig(p) ((p)->Eip)
 # define RIP_sig(p) ((p)->Rip)
 # define RAX_sig(p) ((p)->Rax)
 # define RCX_sig(p) ((p)->Rcx)
 # define RDX_sig(p) ((p)->Rdx)
@@ -1026,24 +1029,35 @@ js::EnsureAsmJSSignalHandlersInstalled(J
 // regular intervals (function prologues, loop headers). For tight loops, this
 // poses non-trivial overhead. For asm.js, we can do better: when another
 // thread requests an interrupt, we simply mprotect all of the innermost asm.js
 // module activation's code. This will trigger a SIGSEGV, taking us into
 // AsmJSFaultHandler. From there, we can manually redirect execution to call
 // js::HandleExecutionInterrupt. The memory is un-protected from the signal
 // handler after control flow is redirected.
 void
-js::RequestInterruptForAsmJSCode(JSRuntime *rt)
+js::RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptModeRaw)
 {
-    JS_ASSERT(rt->currentThreadOwnsInterruptLock());
+    switch (JSRuntime::InterruptMode(interruptModeRaw)) {
+      case JSRuntime::RequestInterruptMainThread:
+      case JSRuntime::RequestInterruptAnyThread:
+        break;
+      case JSRuntime::RequestInterruptAnyThreadDontStopIon:
+      case JSRuntime::RequestInterruptAnyThreadForkJoin:
+        // It is ok to wait for asm.js execution to complete; we aren't trying
+        // to break an iloop or anything. Avoid the overhead of protecting all
+        // the code and taking a fault.
+        return;
+    }
 
     AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread();
     if (!activation)
         return;
 
+    JS_ASSERT(rt->currentThreadOwnsInterruptLock());
     activation->module().protectCode(rt);
 }
 
 #if defined(MOZ_ASAN) && defined(JS_STANDALONE)
 // Usually, this definition is found in mozglue (see mozglue/build/AsanOptions.cpp).
 // However, when doing standalone JS builds, mozglue is not used and we must ensure
 // that we still allow custom SIGSEGV handlers for asm.js and ion to work correctly.
 extern "C" MOZ_ASAN_BLACKLIST
--- a/js/src/jit/AsmJSSignalHandlers.h
+++ b/js/src/jit/AsmJSSignalHandlers.h
@@ -19,17 +19,17 @@ namespace js {
 // Returns whether signal handlers for asm.js and for JitRuntime access
 // violations have been installed.
 bool
 EnsureAsmJSSignalHandlersInstalled(JSRuntime *rt);
 
 // Force any currently-executing asm.js code to call
 // js::HandleExecutionInterrupt.
 extern void
-RequestInterruptForAsmJSCode(JSRuntime *rt);
+RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptMode);
 
 // On OSX we are forced to use the lower-level Mach exception mechanism instead
 // of Unix signals. Mach exceptions are not handled on the victim's stack but
 // rather require an extra thread. For simplicity, we create one such thread
 // per JSRuntime (upon the first use of asm.js in the JSRuntime). This thread
 // and related resources are owned by AsmJSMachExceptionHandler which is owned
 // by JSRuntime.
 #ifdef XP_MACOSX
--- a/js/src/jit/BacktrackingAllocator.cpp
+++ b/js/src/jit/BacktrackingAllocator.cpp
@@ -756,17 +756,17 @@ BacktrackingAllocator::tryAllocateRegist
     if (!reg->isCompatibleReg(r.reg))
         return true;
 
     JS_ASSERT_IF(interval->requirement()->kind() == Requirement::FIXED,
                  interval->requirement()->allocation() == LAllocation(r.reg));
 
     for (size_t i = 0; i < interval->numRanges(); i++) {
         AllocatedRange range(interval, interval->getRange(i)), existing;
-        for (int a = 0; a < r.reg.numAliased(); a++) {
+        for (size_t a = 0; a < r.reg.numAliased(); a++) {
             PhysicalRegister &rAlias = registers[r.reg.aliased(a).code()];
             if (rAlias.allocations.contains(range, &existing)) {
                 if (existing.interval->hasVreg()) {
                     if (IonSpewEnabled(IonSpew_RegAlloc)) {
                     IonSpew(IonSpew_RegAlloc, "  %s collides with v%u[%u] %s [weight %lu]",
                             existing.range->toString(),
                                 rAlias.reg.name(), existing.interval->vreg(),
                                 existing.interval->index(),
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -9,17 +9,16 @@
 #include "mozilla/DebugOnly.h"
 
 #include "jit/IonLinker.h"
 #include "jit/PerfSpewer.h"
 
 #include "jit/IonFrames-inl.h"
 #include "vm/Stack-inl.h"
 
-using namespace mozilla;
 using namespace js;
 using namespace js::jit;
 
 struct DebugModeOSREntry
 {
     JSScript *script;
     BaselineScript *oldBaselineScript;
     ICStub *oldStub;
@@ -119,17 +118,17 @@ struct DebugModeOSREntry
     }
 
     ICFallbackStub *fallbackStub() const {
         MOZ_ASSERT(oldStub);
         return script->baselineScript()->icEntryFromPCOffset(pcOffset).fallbackStub();
     }
 };
 
-typedef js::Vector<DebugModeOSREntry> DebugModeOSREntryVector;
+typedef Vector<DebugModeOSREntry> DebugModeOSREntryVector;
 
 class UniqueScriptOSREntryIter
 {
     const DebugModeOSREntryVector &entries_;
     size_t index_;
 
   public:
     UniqueScriptOSREntryIter(const DebugModeOSREntryVector &entries)
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -612,17 +612,17 @@ JitCompartment::mark(JSTracer *trc, JSCo
         for (ScriptSet::Enum e(*activeParallelEntryScripts_); !e.empty(); e.popFront()) {
             JSScript *script = e.front();
 
             // If the script has since been invalidated or was attached by an
             // off-thread helper too late (i.e., the ForkJoin finished with
             // warmup doing all the work), remove it.
             if (!script->hasParallelIonScript() ||
                 !script->parallelIonScript()->isParallelEntryScript() ||
-                trc->runtime()->gc.shouldCleanUpEverything)
+                trc->runtime()->gc.shouldCleanUpEverything())
             {
                 e.removeFront();
                 continue;
             }
 
             // Check and increment the age. If the script is below the max
             // age, mark it.
             //
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -28,16 +28,17 @@
 #include "jit/VMFunctions.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/Debugger.h"
 #include "vm/ForkJoin.h"
 #include "vm/Interpreter.h"
 #include "vm/TraceLogging.h"
 
 #include "jsscriptinlines.h"
+#include "gc/Nursery-inl.h"
 #include "jit/JitFrameIterator-inl.h"
 #include "vm/Probes-inl.h"
 
 namespace js {
 namespace jit {
 
 // Given a slot index, returns the offset, in bytes, of that slot from an
 // IonJSFrameLayout. Slot distances are uniform across architectures, however,
@@ -940,17 +941,18 @@ MarkIonJSFrame(JSTracer *trc, const JitF
             layout = JSVAL_TO_IMPL(v);
             WriteAllocation(frame, &payload, layout.s.payload.uintptr);
         }
     }
 #endif
 }
 
 #ifdef JSGC_GENERATIONAL
-static void
+template <typename T>
+void
 UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame)
 {
     // Minor GCs may move slots/elements allocated in the nursery. Update
     // any slots/elements pointers stored in this frame.
 
     IonJSFrameLayout *layout = (IonJSFrameLayout *)frame.fp();
 
     IonScript *ionScript = nullptr;
@@ -964,26 +966,18 @@ UpdateIonJSFrameForMinorGC(JSTracer *trc
 
     const SafepointIndex *si = ionScript->getSafepointIndex(frame.returnAddressToFp());
     SafepointReader safepoint(ionScript, si);
 
     GeneralRegisterSet slotsRegs = safepoint.slotsOrElementsSpills();
     uintptr_t *spill = frame.spillBase();
     for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) {
         --spill;
-        if (slotsRegs.has(*iter)) {
-#ifdef JSGC_FJGENERATIONAL
-            if (trc->callback == gc::ForkJoinNursery::MinorGCCallback) {
-                gc::ForkJoinNursery::forwardBufferPointer(trc,
-                                                          reinterpret_cast<HeapSlot **>(spill));
-                continue;
-            }
-#endif
-            trc->runtime()->gc.nursery.forwardBufferPointer(reinterpret_cast<HeapSlot **>(spill));
-        }
+        if (slotsRegs.has(*iter))
+            T::forwardBufferPointer(trc, reinterpret_cast<HeapSlot **>(spill));
     }
 
     // Skip to the right place in the safepoint
     uint32_t slot;
     while (safepoint.getGcSlot(&slot));
     while (safepoint.getValueSlot(&slot));
 #ifdef JS_NUNBOX32
     LAllocation type, payload;
@@ -1273,43 +1267,37 @@ TopmostIonActivationCompartment(JSRuntim
             if (frames.type() == JitFrame_IonJS)
                 return activations.activation()->compartment();
         }
     }
     return nullptr;
 }
 
 #ifdef JSGC_GENERATIONAL
-void
-UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc)
-{
-    JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
-    for (JitActivationIterator activations(rt); !activations.done(); ++activations) {
-        for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
-            if (frames.type() == JitFrame_IonJS)
-                UpdateIonJSFrameForMinorGC(trc, frames);
-        }
-    }
-}
-
-void
-UpdateJitActivationsForMinorGC(PerThreadData *ptd, JSTracer *trc)
+template <typename T>
+void UpdateJitActivationsForMinorGC(PerThreadData *ptd, JSTracer *trc)
 {
 #ifdef JSGC_FJGENERATIONAL
     JS_ASSERT(trc->runtime()->isHeapMinorCollecting() || trc->runtime()->isFJMinorCollecting());
 #else
     JS_ASSERT(trc->runtime()->isHeapMinorCollecting());
 #endif
     for (JitActivationIterator activations(ptd); !activations.done(); ++activations) {
         for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
             if (frames.type() == JitFrame_IonJS)
-                UpdateIonJSFrameForMinorGC(trc, frames);
+                UpdateIonJSFrameForMinorGC<T>(trc, frames);
         }
     }
 }
+
+template
+void UpdateJitActivationsForMinorGC<Nursery>(PerThreadData *ptd, JSTracer *trc);
+
+template
+void UpdateJitActivationsForMinorGC<gc::ForkJoinNursery>(PerThreadData *ptd, JSTracer *trc);
 #endif
 
 void
 AutoTempAllocatorRooter::trace(JSTracer *trc)
 {
     for (CompilerRootNode *root = temp->rootList(); root != nullptr; root = root->next)
         gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
 }
@@ -1344,17 +1332,17 @@ GetPcScript(JSContext *cx, JSScript **sc
     uint8_t *retAddr = it.returnAddress();
     uint32_t hash = PcScriptCache::Hash(retAddr);
     JS_ASSERT(retAddr != nullptr);
 
     // Lazily initialize the cache. The allocation may safely fail and will not GC.
     if (MOZ_UNLIKELY(rt->ionPcScriptCache == nullptr)) {
         rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache));
         if (rt->ionPcScriptCache)
-            rt->ionPcScriptCache->clear(rt->gc.number);
+            rt->ionPcScriptCache->clear(rt->gc.gcNumber());
     }
 
     // Attempt to lookup address in cache.
     if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes))
         return;
 
     // Lookup failed: undertake expensive process to recover the innermost inlined frame.
     ++it; // Skip exit frame.
--- a/js/src/jit/IonFrames.h
+++ b/js/src/jit/IonFrames.h
@@ -266,17 +266,17 @@ void EnsureExitFrame(IonCommonFrameLayou
 
 void MarkJitActivations(PerThreadData *ptd, JSTracer *trc);
 void MarkIonCompilerRoots(JSTracer *trc);
 
 JSCompartment *
 TopmostIonActivationCompartment(JSRuntime *rt);
 
 #ifdef JSGC_GENERATIONAL
-void UpdateJitActivationsForMinorGC(JSRuntime *rt, JSTracer *trc);
+template<typename T>
 void UpdateJitActivationsForMinorGC(PerThreadData *ptd, JSTracer *trc);
 #endif
 
 static inline uint32_t
 MakeFrameDescriptor(uint32_t frameSize, FrameType type)
 {
     return (frameSize << FRAMESIZE_SHIFT) | type;
 }
--- a/js/src/jit/LinearScan.cpp
+++ b/js/src/jit/LinearScan.cpp
@@ -988,41 +988,41 @@ LinearScanAllocator::findBestFreeRegiste
         // all of the float32 and float64 registers.
         AnyRegister reg = regs.takeAny(needFloat);
         freeUntilPos[reg.code()] = CodePosition::MAX;
     }
     for (IntervalIterator i(active.begin()); i != active.end(); i++) {
         LAllocation *alloc = i->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister reg = alloc->toRegister();
-            for (int a = 0; a < reg.numAliased(); a++) {
+            for (size_t a = 0; a < reg.numAliased(); a++) {
                 IonSpew(IonSpew_RegAlloc, "   Register %s not free", reg.aliased(a).name());
                 freeUntilPos[reg.aliased(a).code()] = CodePosition::MIN;
             }
         }
     }
     for (IntervalIterator i(inactive.begin()); i != inactive.end(); i++) {
         LAllocation *alloc = i->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister reg = alloc->toRegister();
             CodePosition pos = current->intersect(*i);
-            for (int a = 0; a < reg.numAliased(); a++) {
+            for (size_t a = 0; a < reg.numAliased(); a++) {
                 if (pos != CodePosition::MIN && pos < freeUntilPos[reg.aliased(a).code()]) {
                     freeUntilPos[reg.aliased(a).code()] = pos;
                     IonSpew(IonSpew_RegAlloc, "   Register %s free until %u", reg.aliased(a).name(), pos.bits());
                 }
             }
         }
     }
 
     CodePosition fixedPos = fixedIntervalsUnion->intersect(current);
     if (fixedPos != CodePosition::MIN) {
         for (IntervalIterator i(fixed.begin()); i != fixed.end(); i++) {
             AnyRegister reg = i->getAllocation()->toRegister();
-            for (int a = 0; a < reg.numAliased(); a++) {
+            for (size_t a = 0; a < reg.numAliased(); a++) {
                 AnyRegister areg = reg.aliased(a);
                 if (freeUntilPos[areg.code()] != CodePosition::MIN) {
                     CodePosition pos = current->intersect(*i);
                     if (pos != CodePosition::MIN && pos < freeUntilPos[areg.code()]) {
                         freeUntilPos[areg.code()] = (pos == current->start()) ? CodePosition::MIN : pos;
                         IonSpew(IonSpew_RegAlloc, "   Register %s free until %u", areg.name(), pos.bits());
                     }
                 }
@@ -1034,48 +1034,48 @@ LinearScanAllocator::findBestFreeRegiste
     if (current->index()) {
         // As an optimization, use the allocation from the previous interval if
         // it is available.
         LiveInterval *previous = vregs[current->vreg()].getInterval(current->index() - 1);
         LAllocation *alloc = previous->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister prevReg = alloc->toRegister();
             bool useit = true;
-            for (int a = 0; a < prevReg.numAliased(); a++) {
+            for (size_t a = 0; a < prevReg.numAliased(); a++) {
                 AnyRegister aprevReg = prevReg.aliased(a);
                 if (freeUntilPos[aprevReg.code()] == CodePosition::MIN) {
                     useit = false;
                     break;
                 }
             }
             if (useit)
                 bestCode = prevReg.code();
         }
     }
 
     // Assign the register suggested by the hint if it's free.
     const Requirement *hint = current->hint();
     if (hint->kind() == Requirement::FIXED && hint->allocation().isRegister()) {
         AnyRegister hintReg = hint->allocation().toRegister();
         bool useit = true;
-        for (int a = 0; a < hintReg.numAliased(); a++) {
+        for (size_t a = 0; a < hintReg.numAliased(); a++) {
             if (freeUntilPos[hintReg.aliased(a).code()] <= hint->pos()) {
                 useit = false;
                 break;
             }
         }
         if (useit)
             bestCode = hintReg.code();
 
     } else if (hint->kind() == Requirement::MUST_REUSE_INPUT) {
         LiveInterval *other = vregs[hint->virtualRegister()].intervalFor(hint->pos());
         if (other && other->getAllocation()->isRegister()) {
             AnyRegister hintReg = other->getAllocation()->toRegister();
             bool useit = true;
-            for (int a = 0; a < hintReg.numAliased(); a++) {
+            for (size_t a = 0; a < hintReg.numAliased(); a++) {
                 if (freeUntilPos[hintReg.aliased(a).code()] <= hint->pos()) {
                     useit = false;
                     break;
                 }
             }
             if (useit)
                 bestCode = hintReg.code();
         }
@@ -1116,17 +1116,17 @@ LinearScanAllocator::findBestBlockedRegi
     for (RegisterSet regs(allRegisters_); !regs.empty(needFloat); ) {
         AnyRegister reg = regs.takeAny(needFloat);
         nextUsePos[reg.code()] = CodePosition::MAX;
     }
     for (IntervalIterator i(active.begin()); i != active.end(); i++) {
         LAllocation *alloc = i->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister fullreg = alloc->toRegister();
-            for (int a = 0; a < fullreg.numAliased(); a++) {
+            for (size_t a = 0; a < fullreg.numAliased(); a++) {
                 AnyRegister reg = fullreg.aliased(a);
                 if (i->start() == current->start()) {
                     nextUsePos[reg.code()] = CodePosition::MIN;
                     IonSpew(IonSpew_RegAlloc, "   Disqualifying %s due to recency", reg.name());
                 } else if (nextUsePos[reg.code()] != CodePosition::MIN) {
                     nextUsePos[reg.code()] = i->nextUsePosAfter(current->start());
                     IonSpew(IonSpew_RegAlloc, "   Register %s next used %u", reg.name(),
                             nextUsePos[reg.code()].bits());
@@ -1134,30 +1134,30 @@ LinearScanAllocator::findBestBlockedRegi
             }
         }
     }
     for (IntervalIterator i(inactive.begin()); i != inactive.end(); i++) {
         LAllocation *alloc = i->getAllocation();
         if (alloc->isRegister(needFloat)) {
             AnyRegister reg = alloc->toRegister();
             CodePosition pos = i->nextUsePosAfter(current->start());
-            for (int a = 0; a < reg.numAliased(); a++) {
+            for (size_t a = 0; a < reg.numAliased(); a++) {
                 if (pos < nextUsePos[reg.aliased(a).code()]) {
                     nextUsePos[reg.aliased(a).code()] = pos;
                     IonSpew(IonSpew_RegAlloc, "   Register %s next used %u", reg.aliased(a).name(), pos.bits());
                 }
             }
         }
     }
 
     CodePosition fixedPos = fixedIntervalsUnion->intersect(current);
     if (fixedPos != CodePosition::MIN) {
         for (IntervalIterator i(fixed.begin()); i != fixed.end(); i++) {
             AnyRegister fullreg = i->getAllocation()->toRegister();
-            for (int a = 0; a < fullreg.numAliased(); a++) {
+            for (size_t a = 0; a < fullreg.numAliased(); a++) {
                 AnyRegister reg = fullreg.aliased(a);
                 if (nextUsePos[reg.code()] != CodePosition::MIN) {
                     CodePosition pos = i->intersect(current);
                     if (pos != CodePosition::MIN && pos < nextUsePos[reg.code()]) {
                         nextUsePos[reg.code()] = (pos == current->start()) ? CodePosition::MIN : pos;
                         IonSpew(IonSpew_RegAlloc, "   Register %s next used %u (fixed)", reg.name(), pos.bits());
                     }
                 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4801,16 +4801,21 @@ class MCharCodeAt
     }
 
     virtual AliasSet getAliasSet() const {
         // Strings are immutable, so there is no implicit dependency.
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
+
+    bool writeRecoverData(CompactBufferWriter &writer) const;
+    bool canRecoverOnBailout() const {
+        return true;
+    }
 };
 
 class MFromCharCode
   : public MUnaryInstruction,
     public IntPolicy<0>
 {
     explicit MFromCharCode(MDefinition *code)
       : MUnaryInstruction(code)
--- a/js/src/jit/PcScriptCache.h
+++ b/js/src/jit/PcScriptCache.h
@@ -40,18 +40,18 @@ struct PcScriptCache
         this->gcNumber = gcNumber;
     }
 
     // Get a value from the cache. May perform lazy allocation.
     bool get(JSRuntime *rt, uint32_t hash, uint8_t *addr,
              JSScript **scriptRes, jsbytecode **pcRes)
     {
         // If a GC occurred, lazily clear the cache now.
-        if (gcNumber != rt->gc.number) {
-            clear(rt->gc.number);
+        if (gcNumber != rt->gc.gcNumber()) {
+            clear(rt->gc.gcNumber());
             return false;
         }
 
         if (entries[hash].returnAddress != addr)
             return false;
 
         *scriptRes = entries[hash].script;
         if (pcRes)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.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 "jit/Recover.h"
 
 #include "jscntxt.h"
 #include "jsmath.h"
+#include "jsstr.h"
 
 #include "builtin/TypedObject.h"
 
 #include "jit/IonSpewer.h"
 #include "jit/JitFrameIterator.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 #include "jit/VMFunctions.h"
@@ -553,16 +554,41 @@ RRound::recover(JSContext *cx, SnapshotI
     if(!js::math_round_handle(cx, arg, &result))
         return false;
 
     iter.storeInstructionResult(result);
     return true;
 }
 
 bool
+MCharCodeAt::writeRecoverData(CompactBufferWriter &writer) const
+{
+    MOZ_ASSERT(canRecoverOnBailout());
+    writer.writeUnsigned(uint32_t(RInstruction::Recover_CharCodeAt));
+    return true;
+}
+
+RCharCodeAt::RCharCodeAt(CompactBufferReader &reader)
+{}
+
+bool
+RCharCodeAt::recover(JSContext *cx, SnapshotIterator &iter) const
+{
+    RootedString lhs(cx, iter.read().toString());
+    RootedValue rhs(cx, iter.read());
+    RootedValue result(cx);
+
+    if (!js::str_charCodeAt_impl(cx, lhs, rhs, &result))
+        return false;
+
+    iter.storeInstructionResult(result);
+    return true;
+}
+
+bool
 MFromCharCode::writeRecoverData(CompactBufferWriter &writer) const
 {
     MOZ_ASSERT(canRecoverOnBailout());
     writer.writeUnsigned(uint32_t(RInstruction::Recover_FromCharCode));
     return true;
 }
 
 RFromCharCode::RFromCharCode(CompactBufferReader &reader)
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -28,16 +28,17 @@ namespace jit {
     _(Add)                                      \
     _(Sub)                                      \
     _(Mul)                                      \
     _(Div)                                      \
     _(Mod)                                      \
     _(Concat)                                   \
     _(Floor)                                    \
     _(Round)                                    \
+    _(CharCodeAt)                               \
     _(FromCharCode)                             \
     _(Pow)                                      \
     _(PowHalf)                                  \
     _(NewObject)                                \
     _(NewDerivedTypedObject)
 
 class RResumePoint;
 class SnapshotIterator;
@@ -292,16 +293,28 @@ class RRound MOZ_FINAL : public RInstruc
 
     virtual uint32_t numOperands() const {
         return 1;
     }
 
     bool recover(JSContext *cx, SnapshotIterator &iter) const;
 };
 
+class RCharCodeAt MOZ_FINAL : public RInstruction
+{
+  public:
+    RINSTRUCTION_HEADER_(CharCodeAt)
+
+    virtual uint32_t numOperands() const {
+        return 2;
+    }
+
+    bool recover(JSContext *cx, SnapshotIterator &iter) const;
+};
+
 class RFromCharCode MOZ_FINAL : public RInstruction
 {
   public:
     RINSTRUCTION_HEADER_(FromCharCode)
 
     virtual uint32_t numOperands() const {
         return 1;
     }
--- a/js/src/jit/arm/Architecture-arm.h
+++ b/js/src/jit/arm/Architecture-arm.h
@@ -330,17 +330,16 @@ class VFPRegister
         JS_ASSERT(isFloat());
         return Code(code_);
     }
     uint32_t id() const {
         return code_;
     }
     static VFPRegister FromCode(uint32_t i) {
         uint32_t code = i & 31;
-        uint32_t kind = i >> 5;
         return VFPRegister(code, Double);
     }
     bool volatile_() const {
         if (isDouble())
             return !!((1 << (code_ >> 1)) & FloatRegisters::VolatileMask);
         return !!((1 << code_) & FloatRegisters::VolatileMask);
     }
     const char *name() const {
@@ -433,22 +432,22 @@ uint32_t GetARMFlags();
 bool HasMOVWT();
 bool HasVFPv3();
 bool HasVFP();
 bool Has32DP();
 bool HasIDIV();
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-static bool hasUnaliasedDouble() {
+inline bool hasUnaliasedDouble() {
     return Has32DP();
 }
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-static bool hasMultiAlias() {
+inline bool hasMultiAlias() {
     return true;
 }
 
 bool ParseARMHwCapFlags(const char *armHwCap);
 
 // If the simulator is used then the ABI choice is dynamic.  Otherwise the ABI is static
 // and useHardFpABI is inlined so that unused branches can be optimized away.
 #if defined(JS_ARM_SIMULATOR)
--- a/js/src/jit/arm/Assembler-arm.cpp
+++ b/js/src/jit/arm/Assembler-arm.cpp
@@ -781,25 +781,25 @@ Assembler::TraceJumpRelocations(JSTracer
 }
 
 static void
 TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
 {
     while (reader.more()) {
         size_t offset = reader.readUnsigned();
         InstructionIterator iter((Instruction*)(buffer+offset));
-        void *ptr = const_cast<uint32_t *>(js::jit::Assembler::getPtr32Target(&iter));
+        void *ptr = const_cast<uint32_t *>(Assembler::getPtr32Target(&iter));
         // No barrier needed since these are constants.
         gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
     }
 
 }
 static void
 TraceDataRelocations(JSTracer *trc, ARMBuffer *buffer,
-                     js::Vector<BufferOffset, 0, SystemAllocPolicy> *locs)
+                     Vector<BufferOffset, 0, SystemAllocPolicy> *locs)
 {
     for (unsigned int idx = 0; idx < locs->length(); idx++) {
         BufferOffset bo = (*locs)[idx];
         ARMBuffer::AssemblerBufferInstIterator iter(bo, buffer);
         void *ptr = const_cast<uint32_t *>(jit::Assembler::getPtr32Target(&iter));
 
         // No barrier needed since these are constants.
         gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -3520,17 +3520,17 @@ MacroAssemblerARMCompat::storePayload(co
     as_dtr(IsStore, 32, Offset, ScratchRegister,
            DTRAddr(dest.base, DtrRegImmShift(dest.index, LSL, shift)));
 }
 
 void
 MacroAssemblerARMCompat::storePayload(Register src, const BaseIndex &dest)
 {
     unsigned shift = ScaleToShift(dest.scale);
-    MOZ_ASSERT(shift < 32 && shift >= 0);
+    MOZ_ASSERT(shift < 32);
     MOZ_ASSERT(dest.offset == 0);
 
     // If NUNBOX32_PAYLOAD_OFFSET is not zero, the memory operand [base + index << shift + imm]
     // cannot be encoded into a single instruction, and cannot be integrated into the as_dtr call.
     JS_STATIC_ASSERT(NUNBOX32_PAYLOAD_OFFSET == 0);
 
     // Technically, shift > -32 can be handle by changing LSL to ASR, but should never come up,
     // and this is one less code path to get wrong.
--- a/js/src/jit/x64/Architecture-x64.h
+++ b/js/src/jit/x64/Architecture-x64.h
@@ -236,21 +236,21 @@ struct FloatRegister {
     static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     uint32_t getRegisterDumpOffsetInBytes();
 
 };
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-static bool hasUnaliasedDouble() {
+inline bool hasUnaliasedDouble() {
     return false;
 }
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-static bool hasMultiAlias() {
+inline bool hasMultiAlias() {
     return false;
 }
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x64_Architecture_x64_h */
--- a/js/src/jit/x86/Architecture-x86.h
+++ b/js/src/jit/x86/Architecture-x86.h
@@ -213,22 +213,22 @@ struct FloatRegister {
     static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister> &s);
     uint32_t getRegisterDumpOffsetInBytes();
 
 
 };
 
 // Arm/D32 has double registers that can NOT be treated as float32
 // and this requires some dances in lowering.
-static bool hasUnaliasedDouble() {
+inline bool hasUnaliasedDouble() {
     return false;
 }
 
 // On ARM, Dn aliases both S2n and S2n+1, so if you need to convert a float32
 // to a double as a temporary, you need a temporary double register.
-static bool hasMultiAlias() {
+inline bool hasMultiAlias() {
     return false;
 }
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_x86_Architecture_x86_h */
--- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp
+++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp
@@ -12,95 +12,95 @@ static bool IsCompartmentGCBuffer[Buffer
 BEGIN_TEST(testGCFinalizeCallback)
 {
     JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
     JS_AddFinalizeCallback(rt, FinalizeCallback, nullptr);
 
     /* Full GC, non-incremental. */
     FinalizeCalls = 0;
     JS_GC(rt);
-    CHECK(rt->gc.isFull);
+    CHECK(rt->gc.isFullGc());
     CHECK(checkSingleGroup());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(false));
 
     /* Full GC, incremental. */
     FinalizeCalls = 0;
     JS::PrepareForFullGC(rt);
     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
     CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
-    CHECK(rt->gc.isFull);
+    CHECK(rt->gc.isFullGc());
     CHECK(checkMultipleGroups());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(false));
 
     JS::RootedObject global1(cx, createGlobal());
     JS::RootedObject global2(cx, createGlobal());
     JS::RootedObject global3(cx, createGlobal());
     CHECK(global1);
     CHECK(global2);
     CHECK(global3);
 
     /* Compartment GC, non-incremental, single compartment. */
     FinalizeCalls = 0;
     JS::PrepareZoneForGC(global1->zone());
     JS::GCForReason(rt, JS::gcreason::API);
-    CHECK(!rt->gc.isFull);
+    CHECK(!rt->gc.isFullGc());
     CHECK(checkSingleGroup());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(true));
 
     /* Compartment GC, non-incremental, multiple compartments. */
     FinalizeCalls = 0;
     JS::PrepareZoneForGC(global1->zone());
     JS::PrepareZoneForGC(global2->zone());
     JS::PrepareZoneForGC(global3->zone());
     JS::GCForReason(rt, JS::gcreason::API);
-    CHECK(!rt->gc.isFull);
+    CHECK(!rt->gc.isFullGc());
     CHECK(checkSingleGroup());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(true));
 
     /* Compartment GC, incremental, single compartment. */
     FinalizeCalls = 0;
     JS::PrepareZoneForGC(global1->zone());
     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
     CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
-    CHECK(!rt->gc.isFull);
+    CHECK(!rt->gc.isFullGc());
     CHECK(checkSingleGroup());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(true));
 
     /* Compartment GC, incremental, multiple compartments. */
     FinalizeCalls = 0;
     JS::PrepareZoneForGC(global1->zone());
     JS::PrepareZoneForGC(global2->zone());
     JS::PrepareZoneForGC(global3->zone());
     JS::IncrementalGC(rt, JS::gcreason::API, 1000000);
     CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
-    CHECK(!rt->gc.isFull);
+    CHECK(!rt->gc.isFullGc());
     CHECK(checkMultipleGroups());
     CHECK(checkFinalizeStatus());
     CHECK(checkFinalizeIsCompartmentGC(true));
 
 #ifdef JS_GC_ZEAL
 
     /* Full GC with reset due to new compartment, becoming compartment GC. */
 
     FinalizeCalls = 0;
     JS_SetGCZeal(cx, 9, 1000000);
     JS::PrepareForFullGC(rt);
     js::GCDebugSlice(rt, true, 1);
     CHECK(rt->gc.state() == js::gc::MARK);
-    CHECK(rt->gc.isFull);
+    CHECK(rt->gc.isFullGc());
 
     JS::RootedObject global4(cx, createGlobal());
     js::GCDebugSlice(rt, true, 1);
     CHECK(rt->gc.state() == js::gc::NO_INCREMENTAL);
-    CHECK(!rt->gc.isFull);
+    CHECK(!rt->gc.isFullGc());
     CHECK(checkMultipleGroups());
     CHECK(checkFinalizeStatus());
 
     for (unsigned i = 0; i < FinalizeCalls - 1; ++i)
         CHECK(!IsCompartmentGCBuffer[i]);
     CHECK(IsCompartmentGCBuffer[FinalizeCalls - 1]);
 
     JS_SetGCZeal(cx, 0, 0);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -68,16 +68,17 @@
 #include "vm/DateObject.h"
 #include "vm/Debugger.h"
 #include "vm/ErrorObject.h"
 #include "vm/HelperThreads.h"
 #include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/RegExpStatics.h"
 #include "vm/Runtime.h"
+#include "vm/SavedStacks.h"
 #include "vm/Shape.h"
 #include "vm/SharedArrayObject.h"
 #include "vm/StopIterationObject.h"
 #include "vm/StringBuffer.h"
 #include "vm/Symbol.h"
 #include "vm/TypedArrayObject.h"
 #include "vm/WeakMapObject.h"
 #include "vm/WrapperObject.h"
@@ -4267,17 +4268,17 @@ struct AutoLastFrameCheck
 #if defined(HAVE_GETC_UNLOCKED)
 # define fast_getc getc_unlocked
 #elif defined(HAVE__GETC_NOLOCK)
 # define fast_getc _getc_nolock
 #else
 # define fast_getc getc
 #endif
 
-typedef js::Vector<char, 8, TempAllocPolicy> FileContents;
+typedef Vector<char, 8, TempAllocPolicy> FileContents;
 
 static bool
 ReadCompleteFile(JSContext *cx, FILE *fp, FileContents &buffer)
 {
     /* Get the complete length of the file, if possible. */
     struct stat st;
     int ok = fstat(fileno(fp), &st);
     if (ok != 0)
@@ -6554,8 +6555,19 @@ JS::SetLargeAllocationFailureCallback(JS
 
 JS_PUBLIC_API(void)
 JS::SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data)
 {
     rt->oomCallback = cb;
     rt->oomCallbackData = data;
 }
 
+JS_PUBLIC_API(bool)
+JS::CaptureCurrentStack(JSContext *cx, JS::MutableHandleObject stackp)
+{
+    JSCompartment *compartment = cx->compartment();
+    JS_ASSERT(compartment);
+    Rooted<SavedFrame *> frame(cx);
+    if (!compartment->savedStacks().saveCurrentStack(cx, &frame))
+        return false;
+    stackp.set(frame.get());
+    return true;
+}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5159,11 +5159,14 @@ SetLargeAllocationFailureCallback(JSRunt
  */
 
 typedef void
 (* OutOfMemoryCallback)(JSContext *cx, void *data);
 
 extern JS_PUBLIC_API(void)
 SetOutOfMemoryCallback(JSRuntime *rt, OutOfMemoryCallback cb, void *data);
 
+extern JS_PUBLIC_API(bool)
+CaptureCurrentStack(JSContext *cx, MutableHandleObject stackp);
+
 } /* namespace JS */
 
 #endif /* jsapi_h */
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -210,28 +210,16 @@ struct ThreadSafeContext : ContextFriend
     ExclusiveContext *asExclusiveContext() const {
         JS_ASSERT(isExclusiveContext());
         return maybeExclusiveContext();
     }
 
     bool isForkJoinContext() const;
     ForkJoinContext *asForkJoinContext();
 
-    // The generational GC nursery may only be used on the main thread.
-#ifdef JSGC_GENERATIONAL
-    inline bool hasNursery() const {
-        return isJSContext();
-    }
-
-    inline js::Nursery &nursery() {
-        JS_ASSERT(hasNursery());
-        return runtime_->gc.nursery;
-    }
-#endif
-
     /*
      * Allocator used when allocating GCThings on this context. If we are a
      * JSContext, this is the Zone allocator of the JSContext's zone.
      * Otherwise, this is a per-thread allocator.
      *
      * This does not live in PerThreadData because the notion of an allocator
      * is only per-thread when off the main thread. The runtime (and the main
      * thread) can have more than one zone, each with its own allocator, and
@@ -548,16 +536,23 @@ struct JSContext : public js::ExclusiveC
                             const JSScript *scr,
                             int entering) const
     {
         if (functionCallback)
             functionCallback(fun, scr, this, entering);
     }
 #endif
 
+    // The generational GC nursery may only be used on the main thread.
+#ifdef JSGC_GENERATIONAL
+    inline js::Nursery &nursery() {
+        return runtime_->gc.nursery;
+    }
+#endif
+
   private:
     /* Innermost-executing generator or null if no generator are executing. */
     JSGenerator *innermostGenerator_;
   public:
     JSGenerator *innermostGenerator() const { return innermostGenerator_; }
     void enterGenerator(JSGenerator *gen);
     void leaveGenerator(JSGenerator *gen);
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -628,17 +628,17 @@ js::TraceWeakMaps(WeakMapTracer *trc)
 {
     WeakMapBase::traceAllMappings(trc);
     WatchpointMap::traceAll(trc);
 }
 
 extern JS_FRIEND_API(bool)
 js::AreGCGrayBitsValid(JSRuntime *rt)
 {
-    return rt->gc.grayBitsValid;
+    return rt->gc.areGrayBitsValid();
 }
 
 JS_FRIEND_API(bool)
 js::ZoneGlobalsAreAllGray(JS::Zone *zone)
 {
     for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
         JSObject *obj = comp->maybeGlobal();
         if (!obj || !JS::GCThingIsMarkedGray(obj))
@@ -858,17 +858,17 @@ JS_FRIEND_API(JS::GCSliceCallback)
 JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback)
 {
     return rt->gc.setSliceCallback(callback);
 }
 
 JS_FRIEND_API(bool)
 JS::WasIncrementalGC(JSRuntime *rt)
 {
-    return rt->gc.isIncremental;
+    return rt->gc.isIncrementalGc();
 }
 
 jschar *
 GCDescription::formatMessage(JSRuntime *rt) const
 {
     return rt->gc.stats.formatMessage();
 }
 
@@ -882,29 +882,29 @@ JS_FRIEND_API(void)
 JS::NotifyDidPaint(JSRuntime *rt)
 {
     rt->gc.notifyDidPaint();
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalGCEnabled(JSRuntime *rt)
 {
-    return rt->gc.isIncrementalGCEnabled() && rt->gcMode() == JSGC_MODE_INCREMENTAL;
+    return rt->gc.isIncrementalGCEnabled();
 }
 
 JS_FRIEND_API(bool)
 JS::IsIncrementalGCInProgress(JSRuntime *rt)
 {
-    return rt->gc.state() != gc::NO_INCREMENTAL && !rt->gc.verifyPreData;
+    return rt->gc.isIncrementalGCInProgress();
 }
 
 JS_FRIEND_API(void)
 JS::DisableIncrementalGC(JSRuntime *rt)
 {
-    rt->gc.disableIncrementalGC();
+    rt->gc.disallowIncrementalGC();
 }
 
 JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt)
   : gc(&rt->gc)
 #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL)
   , restartVerifier(false)
 #endif
 {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -727,22 +727,27 @@ Chunk::allocate(JSRuntime *rt)
 Chunk::release(JSRuntime *rt, Chunk *chunk)
 {
     JS_ASSERT(chunk);
     chunk->prepareToBeFreed(rt);
     FreeChunk(rt, chunk);
 }
 
 inline void
+GCRuntime::updateOnChunkFree(const ChunkInfo &info)
+{
+    JS_ASSERT(numArenasFreeCommitted >= info.numArenasFreeCommitted);
+    numArenasFreeCommitted -= info.numArenasFreeCommitted;
+    stats.count(gcstats::STAT_DESTROY_CHUNK);
+}
+
+inline void
 Chunk::prepareToBeFreed(JSRuntime *rt)
 {
-    JS_ASSERT(rt->gc.numArenasFreeCommitted >= info.numArenasFreeCommitted);
-    rt->gc.numArenasFreeCommitted -= info.numArenasFreeCommitted;
-    rt->gc.stats.count(gcstats::STAT_DESTROY_CHUNK);
-
+    rt->gc.updateOnChunkFree(info);
 #ifdef DEBUG
     /*
      * Let FreeChunkList detect a missing prepareToBeFreed call before it
      * frees chunk.
      */
     info.numArenasFreeCommitted = 0;
 #endif
 }
@@ -860,28 +865,34 @@ Chunk::fetchNextDecommittedArena()
 
     Arena *arena = &arenas[offset];
     info.trailer.runtime->gc.pageAllocator.markPagesInUse(arena, ArenaSize);
     arena->aheader.setAsNotAllocated();
 
     return &arena->aheader;
 }
 
+inline void
+GCRuntime::updateOnFreeArenaAlloc(const ChunkInfo &info)
+{
+    JS_ASSERT(info.numArenasFreeCommitted <= numArenasFreeCommitted);
+    --numArenasFreeCommitted;
+}
+
 inline ArenaHeader *
 Chunk::fetchNextFreeArena(JSRuntime *rt)
 {
     JS_ASSERT(info.numArenasFreeCommitted > 0);
     JS_ASSERT(info.numArenasFreeCommitted <= info.numArenasFree);
-    JS_ASSERT(info.numArenasFreeCommitted <= rt->gc.numArenasFreeCommitted);
 
     ArenaHeader *aheader = info.freeArenasHead;
     info.freeArenasHead = aheader->next;
     --info.numArenasFreeCommitted;
     --info.numArenasFree;
-    --rt->gc.numArenasFreeCommitted;
+    rt->gc.updateOnFreeArenaAlloc(info);
 
     return aheader;
 }
 
 ArenaHeader *
 Chunk::allocateArena(Zone *zone, AllocKind thingKind)
 {
     JS_ASSERT(hasAvailableArenas());
@@ -913,24 +924,30 @@ Chunk::allocateArena(Zone *zone, AllocKi
         AutoUnlockGC unlock(rt);
         TriggerZoneGC(zone, JS::gcreason::ALLOC_TRIGGER);
     }
 
     return aheader;
 }
 
 inline void
+GCRuntime::updateOnArenaFree(const ChunkInfo &info)
+{
+    ++numArenasFreeCommitted;
+}
+
+inline void
 Chunk::addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader)
 {
     JS_ASSERT(!aheader->allocated());
     aheader->next = info.freeArenasHead;
     info.freeArenasHead = aheader;
     ++info.numArenasFreeCommitted;
     ++info.numArenasFree;
-    ++rt->gc.numArenasFreeCommitted;
+    rt->gc.updateOnArenaFree(info);
 }
 
 void
 Chunk::recycleArena(ArenaHeader *aheader, ArenaList &dest, AllocKind thingKind)
 {
     aheader->getArena()->setAsFullyUnused(thingKind);
     dest.insertAtCursor(aheader);
 }
@@ -1057,47 +1074,46 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     rt(rt),
     systemZone(nullptr),
     systemAvailableChunkListHead(nullptr),
     userAvailableChunkListHead(nullptr),
 #ifdef JSGC_GENERATIONAL
     nursery(rt),
     storeBuffer(rt, nursery),
 #endif
+    stats(rt),
+    marker(rt),
     bytes(0),
     maxBytes(0),
     maxMallocBytes(0),
     numArenasFreeCommitted(0),
-    marker(rt),
     verifyPreData(nullptr),
     verifyPostData(nullptr),
     chunkAllocationSinceLastGC(false),
     nextFullGCTime(0),
     lastGCTime(0),
     jitReleaseTime(0),
-    allocationThreshold(30 * 1024 * 1024),
+    allocThreshold(30 * 1024 * 1024),
     highFrequencyGC(false),
     highFrequencyTimeThreshold(1000),
     highFrequencyLowLimitBytes(100 * 1024 * 1024),
     highFrequencyHighLimitBytes(500 * 1024 * 1024),
     highFrequencyHeapGrowthMax(3.0),
     highFrequencyHeapGrowthMin(1.5),
     lowFrequencyHeapGrowth(1.5),
     dynamicHeapGrowth(false),
     dynamicMarkSlice(false),
     decommitThreshold(32 * 1024 * 1024),
-    shouldCleanUpEverything(false),
+    cleanUpEverything(false),
     grayBitsValid(false),
     isNeeded(0),
-    stats(rt),
     number(0),
     startNumber(0),
     isFull(false),
     triggerReason(JS::gcreason::NO_REASON),
-    strictCompartmentChecking(false),
 #ifdef DEBUG
     disableStrictProxyCheckingCount(0),
 #endif
     incrementalState(gc::NO_INCREMENTAL),
     lastMarkSlice(false),
     sweepOnBackgroundThread(false),
     foundBlackGrayEdges(false),
     sweepingZones(nullptr),
@@ -1108,17 +1124,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     sweepKindIndex(0),
     abortSweepAfterCurrentGroup(false),
     arenasAllocatedDuringSweep(nullptr),
 #ifdef JS_GC_MARKING_VALIDATION
     markingValidator(nullptr),
 #endif
     interFrameGC(0),
     sliceBudget(SliceBudget::Unlimited),
-    incrementalEnabled(true),
+    incrementalAllowed(true),
     generationalDisabled(0),
     manipulatingDeadZones(false),
     objectsMarkedInDeadZones(0),
     poked(false),
     heapState(Idle),
 #ifdef JS_GC_ZEAL
     zealMode(0),
     zealFrequency(0),
@@ -1136,16 +1152,17 @@ GCRuntime::GCRuntime(JSRuntime *rt) :
     alwaysPreserveCode(false),
 #ifdef DEBUG
     noGCOrAllocationCheck(0),
 #endif
     lock(nullptr),
     lockOwner(nullptr),
     helperState(rt)
 {
+    setGCMode(JSGC_MODE_GLOBAL);
 }
 
 #ifdef JS_GC_ZEAL
 
 void
 GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
 {
     if (verifyPreData)
@@ -1351,17 +1368,17 @@ GCRuntime::setParameter(JSGCParamKey key
       }
       case JSGC_MAX_MALLOC_BYTES:
         setMaxMallocBytes(value);
         break;
       case JSGC_SLICE_TIME_BUDGET:
         sliceBudget = SliceBudget::TimeBudget(value);
         break;
       case JSGC_MARK_STACK_LIMIT:
-        js::SetMarkStackLimit(rt, value);
+        setMarkStackLimit(value);
         break;
       case JSGC_HIGH_FREQUENCY_TIME_LIMIT:
         highFrequencyTimeThreshold = value;
         break;
       case JSGC_HIGH_FREQUENCY_LOW_LIMIT:
         highFrequencyLowLimitBytes = value * 1024 * 1024;
         break;
       case JSGC_HIGH_FREQUENCY_HIGH_LIMIT:
@@ -1381,17 +1398,17 @@ GCRuntime::setParameter(JSGCParamKey key
         break;
       case JSGC_DYNAMIC_HEAP_GROWTH:
         dynamicHeapGrowth = value;
         break;
       case JSGC_DYNAMIC_MARK_SLICE:
         dynamicMarkSlice = value;
         break;
       case JSGC_ALLOCATION_THRESHOLD:
-        allocationThreshold = value * 1024 * 1024;
+        allocThreshold = value * 1024 * 1024;
         break;
       case JSGC_DECOMMIT_THRESHOLD:
         decommitThreshold = value * 1024 * 1024;
         break;
       default:
         JS_ASSERT(key == JSGC_MODE);
         mode = JSGCMode(value);
         JS_ASSERT(mode == JSGC_MODE_GLOBAL ||
@@ -1407,17 +1424,17 @@ GCRuntime::getParameter(JSGCParamKey key
     switch (key) {
       case JSGC_MAX_BYTES:
         return uint32_t(maxBytes);
       case JSGC_MAX_MALLOC_BYTES:
         return maxMallocBytes;
       case JSGC_BYTES:
         return uint32_t(bytes);
       case JSGC_MODE:
-        return uint32_t(rt->gcMode());
+        return uint32_t(mode);
       case JSGC_UNUSED_CHUNKS:
         return uint32_t(chunkPool.getEmptyCount());
       case JSGC_TOTAL_CHUNKS:
         return uint32_t(chunkSet.count() + chunkPool.getEmptyCount());
       case JSGC_SLICE_TIME_BUDGET:
         return uint32_t(sliceBudget > 0 ? sliceBudget / PRMJ_USEC_PER_MSEC : 0);
       case JSGC_MARK_STACK_LIMIT:
         return marker.maxCapacity();
@@ -1433,23 +1450,31 @@ GCRuntime::getParameter(JSGCParamKey key
         return uint32_t(highFrequencyHeapGrowthMin * 100);
       case JSGC_LOW_FREQUENCY_HEAP_GROWTH:
         return uint32_t(lowFrequencyHeapGrowth * 100);
       case JSGC_DYNAMIC_HEAP_GROWTH:
         return dynamicHeapGrowth;
       case JSGC_DYNAMIC_MARK_SLICE:
         return dynamicMarkSlice;
       case JSGC_ALLOCATION_THRESHOLD:
-        return allocationThreshold / 1024 / 1024;
+        return allocThreshold / 1024 / 1024;
       default:
         JS_ASSERT(key == JSGC_NUMBER);
         return uint32_t(number);
     }
 }
 
+void
+GCRuntime::setMarkStackLimit(size_t limit)
+{
+    JS_ASSERT(!isHeapBusy());
+    AutoStopVerifyingBarriers pauseVerification(rt, false);
+    marker.setMaxCapacity(limit);
+}
+
 template <typename T> struct BarrierOwner {};
 template <typename T> struct BarrierOwner<T *> { typedef T result; };
 template <> struct BarrierOwner<Value> { typedef HeapValue result; };
 
 bool
 GCRuntime::addBlackRootsTracer(JSTraceDataOp traceOp, void *data)
 {
     AssertHeapIsIdle(rt);
@@ -1632,72 +1657,82 @@ GCRuntime::updateMallocCounter(JS::Zone 
 
 void
 GCRuntime::onTooMuchMalloc()
 {
     if (!mallocGCTriggered)
         mallocGCTriggered = triggerGC(JS::gcreason::TOO_MUCH_MALLOC);