Bug 827823 - patch 1 - CC in DOMFile class, r=ehsan
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 26 Jun 2014 20:46:34 -0700
changeset 204919 e94f3dde9619e8bfcbd1743437a323ad83de7df3
parent 204918 57a2c5222c5cebe2fe9e54c11e90a18a7ea67fa3
child 204920 43cbeceed821e92d4cc868e55d885dd6b3011921
push id6561
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 21:23:20 +0000
treeherdermozilla-aurora@428d4d3c8588 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs827823
milestone33.0a1
Bug 827823 - patch 1 - CC in DOMFile class, r=ehsan
content/base/public/nsDOMFile.h
content/base/src/nsDOMBlobBuilder.cpp
content/base/src/nsDOMBlobBuilder.h
content/base/src/nsDOMFile.cpp
content/base/src/nsHostObjectProtocolHandler.cpp
dom/archivereader/ArchiveZipEvent.cpp
dom/archivereader/ArchiveZipFile.cpp
dom/archivereader/ArchiveZipFile.h
dom/base/URL.cpp
dom/base/nsGlobalWindow.cpp
dom/devicestorage/nsDeviceStorage.cpp
dom/filehandle/File.cpp
dom/filehandle/File.h
dom/filehandle/MutableFile.cpp
dom/filesystem/CreateFileTask.cpp
dom/filesystem/CreateFileTask.h
dom/filesystem/GetFileOrDirectoryTask.cpp
dom/filesystem/GetFileOrDirectoryTask.h
dom/indexedDB/IDBMutableFile.cpp
dom/ipc/Blob.cpp
dom/workers/URL.cpp
dom/workers/WorkerPrivate.cpp
--- a/content/base/public/nsDOMFile.h
+++ b/content/base/public/nsDOMFile.h
@@ -34,86 +34,50 @@
 #include "nsWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsDOMMultipartFile;
 class nsIFile;
 class nsIInputStream;
 class nsIClassInfo;
 
+#define PIDOMFILEIMPL_IID \
+  { 0x218ee173, 0xf44f, 0x4d30, \
+    { 0xab, 0x0c, 0xd6, 0x66, 0xea, 0xc2, 0x84, 0x47 } }
+
+class PIDOMFileImpl : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(PIDOMFILEIMPL_IID)
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(PIDOMFileImpl, PIDOMFILEIMPL_IID)
+
 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
+class DOMFile MOZ_FINAL : public nsIDOMFile
+                        , public nsIXHRSendable
+                        , public nsIMutable
+                        , public nsIJSNativeInitializer
 {
-  // XXX bug 827823 will get rid of DOMFileCC
-  friend class DOMFileCC;
-
 public:
   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
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMFile, nsIDOMFile)
 
   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);
@@ -154,46 +118,63 @@ public:
   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)
-  {}
+    : mImpl(aImpl)
+  {
+    MOZ_ASSERT(mImpl);
+  }
+
+  DOMFileImpl* Impl() const
+  {
+    return mImpl;
+  }
+
+  const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const;
+
+  bool IsSizeUnknown() const;
+
+  bool IsDateUnknown() const;
+
+  bool IsFile() const;
 
-protected:
-  virtual ~DOMFile() {};
+  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;
+
+private:
+  ~DOMFile() {};
+
+  // 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.
+  // Note: we should not store any other state in this class!
+  const nsRefPtr<DOMFileImpl> mImpl;
 };
 
-// XXX bug 827823 will get rid of this class
-class DOMFileCC MOZ_FINAL : public DOMFileBase
+// This is the abstract 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 PIDOMFileImpl
 {
 public:
-  DOMFileCC(DOMFileImpl* aImpl)
-    : DOMFileBase(aImpl)
-  {}
-
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMFileCC, nsIDOMFile)
+  NS_DECL_THREADSAFE_ISUPPORTS
 
-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()
-  {
-  }
+  DOMFileImpl() {}
 
   virtual nsresult GetName(nsAString& aName) = 0;
 
   virtual nsresult GetPath(nsAString& aName) = 0;
 
   virtual nsresult
   GetLastModifiedDate(JSContext* aCx,
                       JS::MutableHandle<JS::Value> aDate) = 0;
@@ -210,18 +191,18 @@ public:
 
   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 = 0;
+  virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
+  GetSubBlobImpls() const = 0;
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) = 0;
 
   virtual nsresult
   GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL) = 0;
 
   virtual int64_t GetFileId() = 0;
 
@@ -254,25 +235,28 @@ public:
 
   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;
 
+  virtual bool IsCCed() const
+  {
+    return false;
+  }
+
 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)
@@ -339,18 +323,18 @@ public:
   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
+  virtual const nsTArray<nsRefPtr<DOMFileImpl>>*
+  GetSubBlobImpls() const MOZ_OVERRIDE
   {
     return nullptr;
   }
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual nsresult GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL) MOZ_OVERRIDE;
 
@@ -457,16 +441,18 @@ protected:
 
 /**
  * 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 DOMFileImplMemory MOZ_FINAL : public DOMFileImplBase
 {
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   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");
@@ -551,16 +537,18 @@ private:
 
   // Used when backed by a memory store
   nsRefPtr<DataOwner> mDataOwner;
 };
 
 class DOMFileImplTemporaryFileBlob MOZ_FINAL : public DOMFileImplBase
 {
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   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);
@@ -588,16 +576,18 @@ private:
   uint64_t mStartPos;
   nsRefPtr<nsTemporaryFileInputStream::FileDescOwner> mFileDescOwner;
   nsString mContentType;
 };
 
 class DOMFileImplFile MOZ_FINAL : public DOMFileImplBase
 {
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   // 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");
--- a/content/base/src/nsDOMBlobBuilder.cpp
+++ b/content/base/src/nsDOMBlobBuilder.cpp
@@ -16,16 +16,18 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIXPConnect.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+NS_IMPL_ISUPPORTS_INHERITED0(DOMMultipartFileImpl, DOMFileImpl)
+
 nsresult
 DOMMultipartFileImpl::GetSize(uint64_t* aLength)
 {
   *aLength = mLength;
   return NS_OK;
 }
 
 nsresult
@@ -34,95 +36,95 @@ DOMMultipartFileImpl::GetInternalStream(
   nsresult rv;
   *aStream = nullptr;
 
   nsCOMPtr<nsIMultiplexInputStream> stream =
     do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
   NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);
 
   uint32_t i;
-  for (i = 0; i < mBlobs.Length(); i++) {
+  for (i = 0; i < mBlobImpls.Length(); i++) {
     nsCOMPtr<nsIInputStream> scratchStream;
-    nsIDOMBlob* blob = mBlobs.ElementAt(i).get();
+    DOMFileImpl* blobImpl = mBlobImpls.ElementAt(i).get();
 
-    rv = blob->GetInternalStream(getter_AddRefs(scratchStream));
+    rv = blobImpl->GetInternalStream(getter_AddRefs(scratchStream));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stream->AppendStream(scratchStream);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return CallQueryInterface(stream, aStream);
 }
 
 already_AddRefed<nsIDOMBlob>
 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;
+  nsTArray<nsRefPtr<DOMFileImpl>> blobImpls;
 
   uint64_t length = aLength;
   uint64_t skipStart = aStart;
 
   // Prune the list of blobs if we can
   uint32_t i;
-  for (i = 0; length && skipStart && i < mBlobs.Length(); i++) {
-    nsIDOMBlob* blob = mBlobs[i].get();
+  for (i = 0; length && skipStart && i < mBlobImpls.Length(); i++) {
+    DOMFileImpl* blobImpl = mBlobImpls[i].get();
 
     uint64_t l;
-    nsresult rv = blob->GetSize(&l);
+    nsresult rv = blobImpl->GetSize(&l);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     if (skipStart < l) {
       uint64_t upperBound = std::min<uint64_t>(l - skipStart, length);
 
       nsCOMPtr<nsIDOMBlob> firstBlob;
-      rv = blob->Slice(skipStart, skipStart + upperBound,
-                       aContentType, 3,
-                       getter_AddRefs(firstBlob));
+      rv = blobImpl->Slice(skipStart, skipStart + upperBound,
+                           aContentType, 3,
+                           getter_AddRefs(firstBlob));
       NS_ENSURE_SUCCESS(rv, nullptr);
 
       // Avoid wrapping a single blob inside an DOMMultipartFileImpl
       if (length == upperBound) {
         return firstBlob.forget();
       }
 
-      blobs.AppendElement(firstBlob);
+      blobImpls.AppendElement(static_cast<DOMFile*>(firstBlob.get())->Impl());
       length -= upperBound;
       i++;
       break;
     }
     skipStart -= l;
   }
 
   // Now append enough blobs until we're done
-  for (; length && i < mBlobs.Length(); i++) {
-    nsIDOMBlob* blob = mBlobs[i].get();
+  for (; length && i < mBlobImpls.Length(); i++) {
+    DOMFileImpl* blobImpl = mBlobImpls[i].get();
 
     uint64_t l;
-    nsresult rv = blob->GetSize(&l);
+    nsresult rv = blobImpl->GetSize(&l);
     NS_ENSURE_SUCCESS(rv, nullptr);
 
     if (length < l) {
       nsCOMPtr<nsIDOMBlob> lastBlob;
-      rv = blob->Slice(0, length, aContentType, 3,
-                       getter_AddRefs(lastBlob));
+      rv = blobImpl->Slice(0, length, aContentType, 3,
+                           getter_AddRefs(lastBlob));
       NS_ENSURE_SUCCESS(rv, nullptr);
 
-      blobs.AppendElement(lastBlob);
+      blobImpls.AppendElement(static_cast<DOMFile*>(lastBlob.get())->Impl());
     } else {
-      blobs.AppendElement(blob);
+      blobImpls.AppendElement(blobImpl);
     }
     length -= std::min<uint64_t>(l, length);
   }
 
   // we can create our blob now
   nsCOMPtr<nsIDOMBlob> blob =
-    new DOMFile(new DOMMultipartFileImpl(blobs, aContentType));
+    new DOMFile(new DOMMultipartFileImpl(blobImpls, aContentType));
   return blob.forget();
 }
 
 /* static */ nsresult
 DOMMultipartFileImpl::NewFile(const nsAString& aName, nsISupports** aNewObject)
 {
   nsCOMPtr<nsISupports> file =
     do_QueryObject(new DOMFile(new DOMMultipartFileImpl(aName)));
@@ -220,23 +222,26 @@ DOMMultipartFileImpl::ParseBlobArrayArgu
     JS::Rooted<JS::Value> element(aCx);
     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) {
+        nsRefPtr<DOMFileImpl> blobImpl =
+          static_cast<DOMFile*>(blob.get())->Impl();
+
         // Flatten so that multipart blobs will never nest
-        DOMFile* file = static_cast<DOMFile*>(static_cast<nsIDOMBlob*>(blob));
-        const nsTArray<nsCOMPtr<nsIDOMBlob>>* subBlobs = file->GetSubBlobs();
-        if (subBlobs) {
-          blobSet.AppendBlobs(*subBlobs);
+        const nsTArray<nsRefPtr<DOMFileImpl>>* subBlobImpls =
+          blobImpl->GetSubBlobImpls();
+        if (subBlobImpls) {
+          blobSet.AppendBlobImpls(*subBlobImpls);
         } else {
-          blobSet.AppendBlob(blob);
+          blobSet.AppendBlobImpl(blobImpl);
         }
         continue;
       }
       if (JS_IsArrayBufferViewObject(obj)) {
         nsresult rv = blobSet.AppendVoidPtr(
                                           JS_GetArrayBufferViewData(obj),
                                           JS_GetArrayBufferViewByteLength(obj));
         NS_ENSURE_SUCCESS(rv, rv);
@@ -252,43 +257,37 @@ DOMMultipartFileImpl::ParseBlobArrayArgu
     // coerce it to a string
     JSString* str = JS::ToString(aCx, element);
     NS_ENSURE_TRUE(str, NS_ERROR_TYPE_ERR);
 
     nsresult rv = blobSet.AppendString(str, aNativeEOL, aCx);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  mBlobs = blobSet.GetBlobs();
+  mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
 
   return NS_OK;
 }
 
 void
 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];
+  for (uint32_t index = 0, count = mBlobImpls.Length(); index < count; index++) {
+    nsRefPtr<DOMFileImpl>& blob = mBlobImpls[index];
 
 #ifdef DEBUG
-    {
-      // XXX This is only safe so long as all blob implementations in our tree
-      //     inherit nsDOMFileBase.
-      const auto* blobBase = static_cast<DOMFile*>(blob.get());
-
-      MOZ_ASSERT(!blobBase->IsSizeUnknown());
-      MOZ_ASSERT(!blobBase->IsDateUnknown());
-    }
+    MOZ_ASSERT(!blob->IsSizeUnknown());
+    MOZ_ASSERT(!blob->IsDateUnknown());
 #endif
 
     uint64_t subBlobLength;
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blob->GetSize(&subBlobLength)));
 
     MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
     totalLength += subBlobLength;
   }
@@ -298,27 +297,26 @@ DOMMultipartFileImpl::SetLengthAndModifi
   if (mIsFile) {
     mLastModificationDate = PR_Now();
   }
 }
 
 nsresult
 DOMMultipartFileImpl::GetMozFullPathInternal(nsAString& aFilename)
 {
-  if (!mIsFromNsiFile || mBlobs.Length() == 0) {
+  if (!mIsFromNsiFile || mBlobImpls.Length() == 0) {
     return DOMFileImplBase::GetMozFullPathInternal(aFilename);
   }
 
-  nsIDOMBlob* blob = mBlobs.ElementAt(0).get();
-  if (!blob) {
+  DOMFileImpl* blobImpl = mBlobImpls.ElementAt(0).get();
+  if (!blobImpl) {
     return DOMFileImplBase::GetMozFullPathInternal(aFilename);
   }
 
-  DOMFile* domFile = static_cast<DOMFile*>(blob);
-  return domFile->GetMozFullPathInternal(aFilename);
+  return blobImpl->GetMozFullPathInternal(aFilename);
 }
 
 nsresult
 DOMMultipartFileImpl::InitChromeFile(JSContext* aCx,
                                      uint32_t aArgc,
                                      JS::Value* aArgv)
 {
   nsresult rv;
@@ -407,18 +405,18 @@ DOMMultipartFileImpl::InitChromeFile(JSC
   }
 
   // XXXkhuey this is terrible
   if (mContentType.IsEmpty()) {
     blob->GetType(mContentType);
   }
 
   BlobSet blobSet;
-  blobSet.AppendBlob(blob);
-  mBlobs = blobSet.GetBlobs();
+  blobSet.AppendBlobImpl(static_cast<DOMFile*>(blob.get())->Impl());
+  mBlobImpls = blobSet.GetBlobImpls();
 
   SetLengthAndModifiedDate();
 
   return NS_OK;
 }
 
 nsresult
 DOMMultipartFileImpl::InitFile(JSContext* aCx,
@@ -491,31 +489,31 @@ BlobSet::AppendString(JSString* aString,
 #endif
   }
 
   return AppendVoidPtr((void*)utf8Str.Data(),
                        utf8Str.Length());
 }
 
 nsresult
-BlobSet::AppendBlob(nsIDOMBlob* aBlob)
+BlobSet::AppendBlobImpl(DOMFileImpl* aBlobImpl)
 {
-  NS_ENSURE_ARG_POINTER(aBlob);
+  NS_ENSURE_ARG_POINTER(aBlobImpl);
 
   Flush();
-  mBlobs.AppendElement(aBlob);
+  mBlobImpls.AppendElement(aBlobImpl);
 
   return NS_OK;
 }
 
 nsresult
-BlobSet::AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob)
+BlobSet::AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls)
 {
   Flush();
-  mBlobs.AppendElements(aBlob);
+  mBlobImpls.AppendElements(aBlobImpls);
 
   return NS_OK;
 }
 
 nsresult
 BlobSet::AppendArrayBuffer(JSObject* aBuffer)
 {
   return AppendVoidPtr(JS_GetArrayBufferData(aBuffer),
--- a/content/base/src/nsDOMBlobBuilder.h
+++ b/content/base/src/nsDOMBlobBuilder.h
@@ -15,50 +15,54 @@
 #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 DOMMultipartFileImpl MOZ_FINAL : public mozilla::dom::DOMFileImplBase
+using namespace mozilla::dom;
+
+class DOMMultipartFileImpl MOZ_FINAL : public DOMFileImplBase
 {
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   // Create as a file
-  DOMMultipartFileImpl(const nsTArray<nsCOMPtr<nsIDOMBlob>>& aBlobs,
+  DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
                        const nsAString& aName,
                        const nsAString& aContentType)
-    : mozilla::dom::DOMFileImplBase(aName, aContentType, UINT64_MAX),
-      mBlobs(aBlobs),
+    : DOMFileImplBase(aName, aContentType, UINT64_MAX),
+      mBlobImpls(aBlobImpls),
       mIsFromNsiFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a blob
-  DOMMultipartFileImpl(const nsTArray<nsCOMPtr<nsIDOMBlob>>& aBlobs,
+  DOMMultipartFileImpl(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls,
                        const nsAString& aContentType)
-    : mozilla::dom::DOMFileImplBase(aContentType, UINT64_MAX),
-      mBlobs(aBlobs),
+    : DOMFileImplBase(aContentType, UINT64_MAX),
+      mBlobImpls(aBlobImpls),
       mIsFromNsiFile(false)
   {
     SetLengthAndModifiedDate();
   }
 
   // Create as a file to be later initialized
   explicit DOMMultipartFileImpl(const nsAString& aName)
-    : mozilla::dom::DOMFileImplBase(aName, EmptyString(), UINT64_MAX),
+    : DOMFileImplBase(aName, EmptyString(), UINT64_MAX),
       mIsFromNsiFile(false)
   {
   }
 
   // Create as a blob to be later initialized
   DOMMultipartFileImpl()
-    : mozilla::dom::DOMFileImplBase(EmptyString(), UINT64_MAX),
+    : DOMFileImplBase(EmptyString(), UINT64_MAX),
       mIsFromNsiFile(false)
   {
   }
 
   virtual nsresult
   Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
              const JS::CallArgs& aArgs) MOZ_OVERRIDE;
 
@@ -91,57 +95,57 @@ public:
   //                                                   name: "foo.png" }))
   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
+  virtual const nsTArray<nsRefPtr<DOMFileImpl>>* GetSubBlobImpls() const MOZ_OVERRIDE
   {
-    return &mBlobs;
+    return &mBlobImpls;
   }
 
   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;
+  nsTArray<nsRefPtr<DOMFileImpl>> mBlobImpls;
   bool mIsFromNsiFile;
 };
 
 class BlobSet {
 public:
   BlobSet()
     : mData(nullptr), mDataLen(0), mDataBufferLen(0)
   {}
 
   ~BlobSet()
   {
     moz_free(mData);
   }
 
   nsresult AppendVoidPtr(const void* aData, uint32_t aLength);
   nsresult AppendString(JSString* aString, bool nativeEOL, JSContext* aCx);
-  nsresult AppendBlob(nsIDOMBlob* aBlob);
+  nsresult AppendBlobImpl(DOMFileImpl* aBlobImpl);
   nsresult AppendArrayBuffer(JSObject* aBuffer);
-  nsresult AppendBlobs(const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlob);
+  nsresult AppendBlobImpls(const nsTArray<nsRefPtr<DOMFileImpl>>& aBlobImpls);
 
-  nsTArray<nsCOMPtr<nsIDOMBlob> >& GetBlobs() { Flush(); return mBlobs; }
+  nsTArray<nsRefPtr<DOMFileImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
 
   already_AddRefed<nsIDOMBlob>
   GetBlobInternal(const nsACString& aContentType)
   {
-    nsCOMPtr<nsIDOMBlob> blob = new mozilla::dom::DOMFile(
-      new DOMMultipartFileImpl(GetBlobs(), NS_ConvertASCIItoUTF16(aContentType)));
+    nsCOMPtr<nsIDOMBlob> blob = new DOMFile(
+      new DOMMultipartFileImpl(GetBlobImpls(), NS_ConvertASCIItoUTF16(aContentType)));
     return blob.forget();
   }
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
   {
     using mozilla::CheckedUint32;
 
@@ -169,24 +173,24 @@ protected:
     return true;
   }
 
   void Flush() {
     if (mData) {
       // If we have some data, create a blob for it
       // and put it on the stack
 
-      nsCOMPtr<nsIDOMBlob> blob =
-        mozilla::dom::DOMFile::CreateMemoryFile(mData, mDataLen, EmptyString());
-      mBlobs.AppendElement(blob);
+      nsRefPtr<DOMFileImpl> blobImpl =
+        new DOMFileImplMemory(mData, mDataLen, EmptyString());
+      mBlobImpls.AppendElement(blobImpl);
       mData = nullptr; // The nsDOMMemoryFile takes ownership of the buffer
       mDataLen = 0;
       mDataBufferLen = 0;
     }
   }
 
-  nsTArray<nsCOMPtr<nsIDOMBlob> > mBlobs;
+  nsTArray<nsRefPtr<DOMFileImpl>> mBlobImpls;
   void* mData;
   uint64_t mDataLen;
   uint64_t mDataBufferLen;
 };
 
 #endif
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -120,32 +120,44 @@ nsresult DataOwnerAdapter::Create(DataOw
   NS_ADDREF(*_retval = new DataOwnerAdapter(aDataOwner, stream));
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::DOMFile implementation
 
-NS_INTERFACE_MAP_BEGIN(DOMFile)
+NS_IMPL_CYCLE_COLLECTION_CLASS(DOMFile)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMFile)
+  MOZ_ASSERT(tmp->mImpl);
+  tmp->mImpl->Unlink();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMFile)
+  MOZ_ASSERT(tmp->mImpl);
+  tmp->mImpl->Traverse(cb);
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(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)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMFile)
+NS_IMPL_CYCLE_COLLECTING_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();
@@ -246,109 +258,106 @@ DOMFile::CreateFromFile(nsIFile* aFile, 
 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
+const nsTArray<nsRefPtr<DOMFileImpl>>*
+DOMFile::GetSubBlobImpls() const
 {
-  return mImpl->GetSubBlobs();
+  return mImpl->GetSubBlobImpls();
 }
 
 bool
-DOMFileBase::IsSizeUnknown() const
+DOMFile::IsSizeUnknown() const
 {
   return mImpl->IsSizeUnknown();
 }
 
 bool
-DOMFileBase::IsDateUnknown() const
+DOMFile::IsDateUnknown() const
 {
   return mImpl->IsDateUnknown();
 }
 
 bool
-DOMFileBase::IsFile() const
+DOMFile::IsFile() const
 {
   return mImpl->IsFile();
 }
 
 void
-DOMFileBase::SetLazyData(const nsAString& aName, const nsAString& aContentType,
-                         uint64_t aLength, uint64_t aLastModifiedDate)
+DOMFile::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)
+DOMFile::CreateSlice(uint64_t aStart, uint64_t aLength,
+                     const nsAString& aContentType)
 {
   return mImpl->CreateSlice(aStart, aLength, aContentType);
 }
 
 NS_IMETHODIMP
-DOMFileBase::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
-                        const JS::CallArgs& aArgs)
+DOMFile::Initialize(nsISupports* aOwner, JSContext* aCx, JSObject* aObj,
+                    const JS::CallArgs& aArgs)
 {
   return mImpl->Initialize(aOwner, aCx, aObj, aArgs);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetName(nsAString& aFileName)
+DOMFile::GetName(nsAString& aFileName)
 {
   return mImpl->GetName(aFileName);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetPath(nsAString& aPath)
+DOMFile::GetPath(nsAString& aPath)
 {
   return mImpl->GetPath(aPath);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetLastModifiedDate(JSContext* aCx,
-                                 JS::MutableHandle<JS::Value> aDate)
+DOMFile::GetLastModifiedDate(JSContext* aCx,
+                             JS::MutableHandle<JS::Value> aDate)
 {
   return mImpl->GetLastModifiedDate(aCx, aDate);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetMozFullPath(nsAString &aFileName)
+DOMFile::GetMozFullPath(nsAString &aFileName)
 {
   return mImpl->GetMozFullPath(aFileName);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetMozFullPathInternal(nsAString &aFileName)
+DOMFile::GetMozFullPathInternal(nsAString &aFileName)
 {
   return mImpl->GetMozFullPathInternal(aFileName);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetSize(uint64_t* aSize)
+DOMFile::GetSize(uint64_t* aSize)
 {
   return mImpl->GetSize(aSize);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetType(nsAString &aType)
+DOMFile::GetType(nsAString &aType)
 {
   return mImpl->GetType(aType);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetMozLastModifiedDate(uint64_t* aDate)
+DOMFile::GetMozLastModifiedDate(uint64_t* aDate)
 {
   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)
@@ -381,77 +390,77 @@ ParseSize(int64_t aSize, int64_t& aStart
   }
   else {
     aStart = newStartOffset.value();
     aEnd = newEndOffset.value();
   }
 }
 
 NS_IMETHODIMP
-DOMFileBase::Slice(int64_t aStart, int64_t aEnd,
-                   const nsAString& aContentType, uint8_t aArgc,
-                   nsIDOMBlob **aBlob)
+DOMFile::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)
+DOMFile::GetInternalStream(nsIInputStream** aStream)
 {
  return mImpl->GetInternalStream(aStream);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
+DOMFile::GetInternalUrl(nsIPrincipal* aPrincipal, nsAString& aURL)
 {
   return mImpl->GetInternalUrl(aPrincipal, aURL);
 }
 
 NS_IMETHODIMP_(int64_t)
-DOMFileBase::GetFileId()
+DOMFile::GetFileId()
 {
   return mImpl->GetFileId();
 }
 
 NS_IMETHODIMP_(void)
-DOMFileBase::AddFileInfo(indexedDB::FileInfo* aFileInfo)
+DOMFile::AddFileInfo(indexedDB::FileInfo* aFileInfo)
 {
   mImpl->AddFileInfo(aFileInfo);
 }
 
 indexedDB::FileInfo*
-DOMFileBase::GetFileInfo(indexedDB::FileManager* aFileManager)
+DOMFile::GetFileInfo(indexedDB::FileManager* aFileManager)
 {
   return mImpl->GetFileInfo(aFileManager);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetSendInfo(nsIInputStream** aBody,
-                         uint64_t* aContentLength,
-                         nsACString& aContentType,
-                         nsACString& aCharset)
+DOMFile::GetSendInfo(nsIInputStream** aBody,
+                     uint64_t* aContentLength,
+                     nsACString& aContentType,
+                     nsACString& aCharset)
 {
   return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
 }
 
 NS_IMETHODIMP
-DOMFileBase::GetMutable(bool* aMutable)
+DOMFile::GetMutable(bool* aMutable)
 {
   return mImpl->GetMutable(aMutable);
 }
 
 NS_IMETHODIMP
-DOMFileBase::SetMutable(bool aMutable)
+DOMFile::SetMutable(bool aMutable)
 {
   return mImpl->SetMutable(aMutable);
 }
 
 NS_IMETHODIMP_(bool)
-DOMFileBase::IsMemoryFile()
+DOMFile::IsMemoryFile()
 {
   return mImpl->IsMemoryFile();
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::DOMFileImpl implementation
 
 nsresult
@@ -476,17 +485,24 @@ DOMFileImpl::Slice(int64_t aStart, int64
   nsCOMPtr<nsIDOMBlob> blob =
     CreateSlice((uint64_t)aStart, (uint64_t)(aEnd - aStart), aContentType);
 
   blob.forget(aBlob);
   return *aBlob ? NS_OK : NS_ERROR_UNEXPECTED;
 }
 
 ////////////////////////////////////////////////////////////////////////////
-// DOMFileImplBase implementation
+// DOMFileImpl implementation
+
+NS_IMPL_ISUPPORTS(DOMFileImpl, PIDOMFileImpl)
+
+////////////////////////////////////////////////////////////////////////////
+// DOMFileImplFile implementation
+
+NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplFile, DOMFileImpl)
 
 nsresult
 DOMFileImplBase::GetName(nsAString& aName)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
   aName = mName;
   return NS_OK;
 }
@@ -722,45 +738,16 @@ DOMFileImplBase::SetMutable(bool aMutabl
     rv = this->GetSize(&dummyInt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mImmutable = !aMutable;
   return rv;
 }
 
-NS_IMPL_ISUPPORTS0(DOMFileImplBase)
-
-////////////////////////////////////////////////////////////////////////////
-// DOMFileCC implementation
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(DOMFileCC)
-
-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(DOMFileCC)
-  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_CYCLE_COLLECTING_ADDREF(DOMFileCC)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMFileCC)
-
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplFile implementation
 
 already_AddRefed<nsIDOMBlob>
 DOMFileImplFile::CreateSlice(uint64_t aStart, uint64_t aLength,
                              const nsAString& aContentType)
 {
   nsCOMPtr<nsIDOMBlob> blob =
@@ -885,16 +872,18 @@ DOMFileImplFile::SetPath(const nsAString
              aPath[aPath.Length() - 1] == char16_t('/'),
              "Path must end with a path separator");
   mPath = aPath;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplMemory implementation
 
+NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplMemory, DOMFileImpl)
+
 already_AddRefed<nsIDOMBlob>
 DOMFileImplMemory::CreateSlice(uint64_t aStart, uint64_t aLength,
                                const nsAString& aContentType)
 {
   nsCOMPtr<nsIDOMBlob> blob =
     new DOMFile(new DOMFileImplMemory(this, aStart, aLength, aContentType));
   return blob.forget();
 }
@@ -1008,16 +997,18 @@ DOMFileImplMemory::DataOwner::EnsureMemo
   RegisterStrongMemoryReporter(new DOMFileImplMemoryDataOwnerMemoryReporter());
 
   sMemoryReporterRegistered = true;
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // DOMFileImplTemporaryFileBlob implementation
 
+NS_IMPL_ISUPPORTS_INHERITED0(DOMFileImplTemporaryFileBlob, DOMFileImpl)
+
 already_AddRefed<nsIDOMBlob>
 DOMFileImplTemporaryFileBlob::CreateSlice(uint64_t aStart, uint64_t aLength,
                                           const nsAString& aContentType)
 {
   if (aStart + aLength > mLength)
     return nullptr;
 
   nsCOMPtr<nsIDOMBlob> blob =
--- a/content/base/src/nsHostObjectProtocolHandler.cpp
+++ b/content/base/src/nsHostObjectProtocolHandler.cpp
@@ -5,22 +5,24 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHostObjectProtocolHandler.h"
 #include "nsHostObjectURI.h"
 #include "nsError.h"
 #include "nsClassHashtable.h"
 #include "nsNetUtil.h"
 #include "nsIPrincipal.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "nsIDOMMediaStream.h"
 #include "mozilla/dom/MediaSource.h"
 #include "nsIMemoryReporter.h"
 #include "mozilla/Preferences.h"
 
+using mozilla::dom::DOMFileImpl;
+
 // -----------------------------------------------------------------------
 // Hash table
 struct DataInfo
 {
   // mObject is expected to be an nsIDOMBlob, nsIDOMMediaStream, or MediaSource
   nsCOMPtr<nsISupports> mObject;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsCString mStack;
@@ -473,50 +475,51 @@ nsHostObjectProtocolHandler::NewChannel(
   nsCString spec;
   uri->GetSpec(spec);
 
   DataInfo* info = GetDataInfo(spec);
 
   if (!info) {
     return NS_ERROR_DOM_BAD_URI;
   }
-  nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(info->mObject);
-  if (!blob) {
+
+  nsCOMPtr<PIDOMFileImpl> blobImpl = do_QueryInterface(info->mObject);
+  if (!blobImpl) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
 #ifdef DEBUG
   {
     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(uri);
     nsCOMPtr<nsIPrincipal> principal;
     uriPrinc->GetPrincipal(getter_AddRefs(principal));
     NS_ASSERTION(info->mPrincipal == principal, "Wrong principal!");
   }
 #endif
 
+  DOMFileImpl* blob = static_cast<DOMFileImpl*>(blobImpl.get());
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = blob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
                                 uri,
                                 stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
 
   nsString type;
   rv = blob->GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<nsIDOMFile> file = do_QueryInterface(info->mObject);
-  if (file) {
+  if (blob->IsFile()) {
     nsString filename;
-    rv = file->GetName(filename);
+    rv = blob->GetName(filename);
     NS_ENSURE_SUCCESS(rv, rv);
     channel->SetContentDispositionFilename(filename);
   }
 
   uint64_t size;
   rv = blob->GetSize(&size);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -569,21 +572,22 @@ nsFontTableProtocolHandler::GetScheme(ns
 
 nsresult
 NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
 {
   NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
 
   *aStream = nullptr;
 
-  nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(GetDataObject(aURI));
-  if (!blob) {
+  nsCOMPtr<PIDOMFileImpl> blobImpl = do_QueryInterface(GetDataObject(aURI));
+  if (!blobImpl) {
     return NS_ERROR_DOM_BAD_URI;
   }
 
+  DOMFileImpl* blob = static_cast<DOMFileImpl*>(blobImpl.get());
   return blob->GetInternalStream(aStream);
 }
 
 nsresult
 NS_GetStreamForMediaStreamURI(nsIURI* aURI, nsIDOMMediaStream** aStream)
 {
   NS_ASSERTION(IsMediaStreamURI(aURI), "Only call this with mediastream URIs");
 
--- a/dom/archivereader/ArchiveZipEvent.cpp
+++ b/dom/archivereader/ArchiveZipEvent.cpp
@@ -79,17 +79,17 @@ nsIDOMFile*
 ArchiveZipItem::File(ArchiveReader* aArchiveReader)
 {
   nsString filename;
 
   if (NS_FAILED(GetFilename(filename))) {
     return nullptr;
   }
 
-  return new DOMFileCC(
+  return new DOMFile(
     new ArchiveZipFileImpl(filename,
                            NS_ConvertUTF8toUTF16(GetType()),
                            StrToInt32(mCentralStruct.orglen),
                            mCentralStruct, aArchiveReader));
 }
 
 uint32_t
 ArchiveZipItem::StrToInt32(const uint8_t* aStr)
--- a/dom/archivereader/ArchiveZipFile.cpp
+++ b/dom/archivereader/ArchiveZipFile.cpp
@@ -397,13 +397,15 @@ ArchiveZipFileImpl::Traverse(nsCycleColl
 }
 
 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));
+    new DOMFile(new ArchiveZipFileImpl(mFilename, mContentType,
+                                       aStart, mLength, mCentral,
+                                       mArchiveReader));
   return t.forget();
 }
+
+NS_IMPL_ISUPPORTS_INHERITED0(ArchiveZipFileImpl, DOMFileImpl)
--- a/dom/archivereader/ArchiveZipFile.h
+++ b/dom/archivereader/ArchiveZipFile.h
@@ -18,16 +18,18 @@
 BEGIN_ARCHIVEREADER_NAMESPACE
 
 /**
  * ArchiveZipFileImpl to DOMFileImpl
  */
 class ArchiveZipFileImpl : public DOMFileImplBase
 {
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   ArchiveZipFileImpl(const nsAString& aName,
                      const nsAString& aContentType,
                      uint64_t aLength,
                      ZipCentral& aCentral,
                      ArchiveReader* aReader)
   : DOMFileImplBase(aName, aContentType, aLength),
     mCentral(aCentral),
     mArchiveReader(aReader),
@@ -58,16 +60,21 @@ public:
   }
 
   // Overrides:
   virtual nsresult GetInternalStream(nsIInputStream**) MOZ_OVERRIDE;
 
   virtual void Unlink() MOZ_OVERRIDE;
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
+  virtual bool IsCCed() const MOZ_OVERRIDE
+  {
+    return true;
+  }
+
 protected:
   virtual already_AddRefed<nsIDOMBlob> CreateSlice(uint64_t aStart,
                                                    uint64_t aLength,
                                                    const nsAString& aContentType) MOZ_OVERRIDE;
 
 private: // Data
   ZipCentral mCentral;
   nsRefPtr<ArchiveReader> mArchiveReader;
--- a/dom/base/URL.cpp
+++ b/dom/base/URL.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "URL.h"
 
 #include "nsGlobalWindow.h"
-#include "nsIDOMFile.h"
+#include "nsDOMFile.h"
 #include "DOMMediaStream.h"
 #include "mozilla/dom/MediaSource.h"
 #include "mozilla/dom/URLBinding.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIIOService.h"
 #include "nsEscape.h"
 #include "nsNetCID.h"
@@ -111,17 +111,20 @@ URL::Constructor(const GlobalObject& aGl
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal,
                      nsIDOMBlob* aBlob,
                      const objectURLOptions& aOptions,
                      nsString& aResult,
                      ErrorResult& aError)
 {
-  CreateObjectURLInternal(aGlobal, aBlob,
+  DOMFile* blob = static_cast<DOMFile*>(aBlob);
+  MOZ_ASSERT(blob);
+
+  CreateObjectURLInternal(aGlobal, blob->Impl(),
                           NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
                           aError);
 }
 
 void
 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
                      const mozilla::dom::objectURLOptions& aOptions,
                      nsString& aResult,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7835,17 +7835,32 @@ struct StructuredCloneInfo {
 
 static JSObject*
 PostMessageReadStructuredClone(JSContext* cx,
                                JSStructuredCloneReader* reader,
                                uint32_t tag,
                                uint32_t data,
                                void* closure)
 {
-  if (tag == SCTAG_DOM_BLOB || tag == SCTAG_DOM_FILELIST) {
+  if (tag == SCTAG_DOM_BLOB) {
+    NS_ASSERTION(!data, "Data should be empty");
+
+    // What we get back from the reader is a DOMFileImpl.
+    // From that we create a new DOMFile.
+    nsISupports* supports;
+    if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
+      nsCOMPtr<nsIDOMBlob> file = new DOMFile(static_cast<DOMFileImpl*>(supports));
+      JS::Rooted<JS::Value> val(cx);
+      if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, file, &val))) {
+        return val.toObjectOrNull();
+      }
+    }
+  }
+
+  if (tag == SCTAG_DOM_FILELIST) {
     NS_ASSERTION(!data, "Data should be empty");
 
     nsISupports* supports;
     if (JS_ReadBytes(reader, &supports, sizeof(supports))) {
       JS::Rooted<JS::Value> val(cx);
       if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) {
         return val.toObjectOrNull();
       }
@@ -7874,18 +7889,21 @@ PostMessageWriteStructuredClone(JSContex
   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative));
   if (wrappedNative) {
     uint32_t scTag = 0;
     nsISupports* supports = wrappedNative->Native();
 
     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
-    if (blob && scInfo->subsumes)
+    if (blob && scInfo->subsumes) {
       scTag = SCTAG_DOM_BLOB;
+      DOMFile* file = static_cast<DOMFile*>(blob.get());
+      supports = file->Impl();
+    }
 
     nsCOMPtr<nsIDOMFileList> list = do_QueryInterface(supports);
     if (list && scInfo->subsumes)
       scTag = SCTAG_DOM_FILELIST;
 
     if (scTag)
       return JS_WriteUint32Pair(writer, scTag, 0) &&
              JS_WriteBytes(writer, &supports, sizeof(supports)) &&
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -2391,38 +2391,38 @@ public:
 private:
   nsRefPtr<DeviceStorageFileDescriptor> mDSFileDescriptor;
   nsRefPtr<DOMRequest> mRequest;
 };
 
 class WriteFileEvent : public nsRunnable
 {
 public:
-  WriteFileEvent(nsIDOMBlob* aBlob,
+  WriteFileEvent(DOMFileImpl* aBlobImpl,
                  DeviceStorageFile *aFile,
                  already_AddRefed<DOMRequest> aRequest,
                  int32_t aRequestType)
-    : mBlob(aBlob)
+    : mBlobImpl(aBlobImpl)
     , mFile(aFile)
     , mRequest(aRequest)
     , mRequestType(aRequestType)
   {
     MOZ_ASSERT(mFile);
     MOZ_ASSERT(mRequest);
     MOZ_ASSERT(mRequestType);
   }
 
   ~WriteFileEvent() {}
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
     nsCOMPtr<nsIInputStream> stream;
-    mBlob->GetInternalStream(getter_AddRefs(stream));
+    mBlobImpl->GetInternalStream(getter_AddRefs(stream));
 
     bool check = false;
     mFile->mFile->Exists(&check);
     nsresult rv;
 
     if (mRequestType == DEVICE_STORAGE_REQUEST_APPEND) {
       if (!check) {
         nsCOMPtr<nsIRunnable> event =
@@ -2456,17 +2456,17 @@ public:
     nsString fullPath;
     mFile->GetFullPath(fullPath);
     nsCOMPtr<nsIRunnable> event =
       new PostResultEvent(mRequest.forget(), fullPath);
     return NS_DispatchToMainThread(event);
   }
 
 private:
-  nsCOMPtr<nsIDOMBlob> mBlob;
+  nsRefPtr<DOMFileImpl> mBlobImpl;
   nsRefPtr<DeviceStorageFile> mFile;
   nsRefPtr<DOMRequest> mRequest;
   int32_t mRequestType;
 };
 
 
 class ReadFileEvent : public nsRunnable
 {
@@ -2882,17 +2882,20 @@ public:
           params.relpath() = mFile->mPath;
 
           PDeviceStorageRequestChild* child
             = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()
             ->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
-        r = new WriteFileEvent(mBlob, mFile, mRequest.forget(), mRequestType);
+
+        DOMFile* blob = static_cast<DOMFile*>(mBlob.get());
+        r = new WriteFileEvent(blob->Impl(), mFile, mRequest.forget(),
+                               mRequestType);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_APPEND:
       {
         if (!mBlob || !mFile->mFile) {
           return NS_ERROR_FAILURE;
         }
@@ -2924,17 +2927,20 @@ public:
           params.relpath() = mFile->mPath;
 
           PDeviceStorageRequestChild* child
             = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()
             ->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
-        r = new WriteFileEvent(mBlob, mFile, mRequest.forget(), mRequestType);
+
+        DOMFile* blob = static_cast<DOMFile*>(mBlob.get());
+        r = new WriteFileEvent(blob->Impl(), mFile, mRequest.forget(),
+                               mRequestType);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_READ:
       case DEVICE_STORAGE_REQUEST_WRITE:
       {
         if (!mFile->mFile) {
           return NS_ERROR_FAILURE;
--- a/dom/filehandle/File.cpp
+++ b/dom/filehandle/File.cpp
@@ -10,16 +10,18 @@
 #include "mozilla/Assertions.h"
 #include "nsDebug.h"
 
 namespace mozilla {
 namespace dom {
 
 using indexedDB::IndexedDatabaseManager;
 
+NS_IMPL_ISUPPORTS_INHERITED0(FileImpl, DOMFileImpl)
+
 // 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!");
@@ -94,17 +96,17 @@ FileImpl::GetInternalStream(nsIInputStre
 
 already_AddRefed<nsIDOMBlob>
 FileImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
                       const nsAString& aContentType)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIDOMBlob> t =
-    new DOMFileCC(new FileImpl(this, aStart, aLength, aContentType));
+    new DOMFile(new FileImpl(this, aStart, aLength, aContentType));
 
   return t.forget();
 }
 
 nsresult
 FileImpl::GetMozFullPathInternal(nsAString& aFilename)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
--- a/dom/filehandle/File.h
+++ b/dom/filehandle/File.h
@@ -19,16 +19,18 @@ namespace dom {
 class FileHandle;
 class File;
 
 class FileImpl : public DOMFileImplBase
 {
   friend class File;
 
 public:
+  NS_DECL_ISUPPORTS_INHERITED
+
   // Create as a file
   FileImpl(const nsAString& aName, const nsAString& aContentType,
            uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle);
 
   // Create as a stored file
   FileImpl(const nsAString& aName, const nsAString& aContentType,
            uint64_t aLength, nsIFile* aFile, FileHandle* aFileHandle,
            indexedDB::FileInfo* aFileInfo);
@@ -36,16 +38,21 @@ public:
   // Overrides
   virtual nsresult GetMozFullPathInternal(nsAString& aFullPath) MOZ_OVERRIDE;
 
   virtual nsresult GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
 
   virtual void Unlink() MOZ_OVERRIDE;
   virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) MOZ_OVERRIDE;
 
+  virtual bool IsCCed() const MOZ_OVERRIDE
+  {
+    return true;
+  }
+
 protected:
   // Create slice
   FileImpl(const FileImpl* aOther, uint64_t aStart, uint64_t aLength,
            const nsAString& aContentType);
 
   virtual ~FileImpl();
 
   virtual already_AddRefed<nsIDOMBlob>
--- 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 DOMFileCC(new FileImpl(mName, mType, aFileSize, mFile, aFileHandle));
+    new DOMFile(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
@@ -114,33 +114,34 @@ CreateFileTask::GetRequestParams(const n
   }
   return param;
 }
 
 FileSystemResponseValue
 CreateFileTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
-  BlobParent* actor = GetBlobParent(mTargetFile);
+  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
 void
 CreateFileTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   FileSystemFileResponse r = aValue;
   BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
   nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-  mTargetFile = do_QueryInterface(blob);
+  mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
 }
 
 nsresult
 CreateFileTask::Work()
 {
   class AutoClose
   {
   public:
@@ -247,17 +248,17 @@ CreateFileTask::Work()
 
     mBlobStream->Close();
     mBlobStream = nullptr;
 
     if (mFileSystem->IsShutdown()) {
       return NS_ERROR_FAILURE;
     }
 
-    mTargetFile = DOMFile::CreateFromFile(file);
+    mTargetFileImpl = new DOMFileImplFile(file);
     return NS_OK;
   }
 
   // Write file content from array data.
 
   uint32_t written;
   rv = bufferedOutputStream->Write(
     reinterpret_cast<char*>(mArrayData.Elements()),
@@ -266,17 +267,17 @@ CreateFileTask::Work()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   if (mArrayData.Length() != written) {
     return NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
   }
 
-  mTargetFile = DOMFile::CreateFromFile(file);
+  mTargetFileImpl = new DOMFileImplFile(file);
   return NS_OK;
 }
 
 void
 CreateFileTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mFileSystem->IsShutdown()) {
@@ -287,17 +288,18 @@ CreateFileTask::HandlerCallback()
   if (HasError()) {
     nsRefPtr<DOMError> domError = new DOMError(mFileSystem->GetWindow(),
       mErrorValue);
     mPromise->MaybeRejectBrokenly(domError);
     mPromise = nullptr;
     return;
   }
 
-  mPromise->MaybeResolve(mTargetFile);
+  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  mPromise->MaybeResolve(file);
   mPromise = nullptr;
 }
 
 void
 CreateFileTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   if (mReplace) {
     aAccess.AssignLiteral("write");
--- a/dom/filesystem/CreateFileTask.h
+++ b/dom/filesystem/CreateFileTask.h
@@ -11,16 +11,17 @@
 #include "nsAutoPtr.h"
 
 class nsIDOMBlob;
 class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 
+class DOMFileImpl;
 class Promise;
 
 class CreateFileTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   CreateFileTask(FileSystemBase* aFileSystem,
                  const nsAString& aPath,
@@ -62,15 +63,18 @@ private:
 
   static uint32_t sOutputBufferSize;
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
   nsCOMPtr<nsIDOMBlob> mBlobData;
   nsCOMPtr<nsIInputStream> mBlobStream;
   InfallibleTArray<uint8_t> mArrayData;
   bool mReplace;
-  nsCOMPtr<nsIDOMFile> mTargetFile;
+
+  // This cannot be a DOMFile bacause this object is created on a different
+  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
+  nsRefPtr<DOMFileImpl> mTargetFileImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_CreateFileTask_h
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -72,17 +72,19 @@ GetFileOrDirectoryTask::GetRequestParams
 
 FileSystemResponseValue
 GetFileOrDirectoryTask::GetSuccessRequestResult() const
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   if (mIsDirectory) {
     return FileSystemDirectoryResponse(mTargetRealPath);
   }
-  BlobParent* actor = GetBlobParent(mTargetFile);
+
+  nsRefPtr<DOMFile> file = new DOMFile(mTargetFileImpl);
+  BlobParent* actor = GetBlobParent(file);
   if (!actor) {
     return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
   }
   FileSystemFileResponse response;
   response.blobParent() = actor;
   return response;
 }
 
@@ -90,17 +92,17 @@ void
 GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
   switch (aValue.type()) {
     case FileSystemResponseValue::TFileSystemFileResponse: {
       FileSystemFileResponse r = aValue;
       BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
       nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
-      mTargetFile = do_QueryInterface(blob);
+      mTargetFileImpl = static_cast<DOMFile*>(blob.get())->Impl();
       mIsDirectory = false;
       break;
     }
     case FileSystemResponseValue::TFileSystemDirectoryResponse: {
       FileSystemDirectoryResponse r = aValue;
       mTargetRealPath = r.realPath();
       mIsDirectory = true;
       break;
@@ -175,17 +177,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 = DOMFile::CreateFromFile(file);
+  mTargetFileImpl = new DOMFileImplFile(file);
 
   return NS_OK;
 }
 
 void
 GetFileOrDirectoryTask::HandlerCallback()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
@@ -204,17 +206,18 @@ GetFileOrDirectoryTask::HandlerCallback(
 
   if (mIsDirectory) {
     nsRefPtr<Directory> dir = new Directory(mFileSystem, mTargetRealPath);
     mPromise->MaybeResolve(dir);
     mPromise = nullptr;
     return;
   }
 
-  mPromise->MaybeResolve(mTargetFile);
+  nsCOMPtr<nsIDOMFile> file = new DOMFile(mTargetFileImpl);
+  mPromise->MaybeResolve(file);
   mPromise = nullptr;
 }
 
 void
 GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
 {
   aAccess.AssignLiteral("read");
 }
--- a/dom/filesystem/GetFileOrDirectoryTask.h
+++ b/dom/filesystem/GetFileOrDirectoryTask.h
@@ -8,16 +8,18 @@
 #define mozilla_dom_GetFileOrDirectory_h
 
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "nsAutoPtr.h"
 
 namespace mozilla {
 namespace dom {
 
+class DOMFileImpl;
+
 class GetFileOrDirectoryTask MOZ_FINAL
   : public FileSystemTaskBase
 {
 public:
   // If aDirectoryOnly is set, we should ensure that the target is a directory.
   GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
                          const nsAString& aTargetPath,
                          bool aDirectoryOnly);
@@ -49,15 +51,18 @@ protected:
   virtual void
   HandlerCallback() MOZ_OVERRIDE;
 
 private:
   nsRefPtr<Promise> mPromise;
   nsString mTargetRealPath;
   // Whether we get a directory.
   bool mIsDirectory;
-  nsCOMPtr<nsIDOMFile> mTargetFile;
+
+  // This cannot be a DOMFile bacause this object is created on a different
+  // thread and DOMFile is not thread-safe. Let's use the DOMFileImpl instead.
+  nsRefPtr<DOMFileImpl> mTargetFileImpl;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_GetFileOrDirectory_h
--- a/dom/indexedDB/IDBMutableFile.cpp
+++ b/dom/indexedDB/IDBMutableFile.cpp
@@ -134,17 +134,17 @@ IDBMutableFile::UnsetThreadLocals()
 {
   QuotaManager::SetCurrentWindow(nullptr);
 }
 
 already_AddRefed<nsIDOMFile>
 IDBMutableFile::CreateFileObject(mozilla::dom::FileHandle* aFileHandle,
                                 uint32_t aFileSize)
 {
-  nsCOMPtr<nsIDOMFile> file = new DOMFileCC(
+  nsCOMPtr<nsIDOMFile> file = new DOMFile(
     new FileImpl(mName, mType, aFileSize, mFile, aFileHandle, mFileInfo));
 
   return file.forget();
 }
 
 // virtual
 JSObject*
 IDBMutableFile::WrapObject(JSContext* aCx)
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -865,17 +865,17 @@ private:
   }
 };
 
 class BlobChild::RemoteBlob::SliceHelper MOZ_FINAL
   : public nsRunnable
 {
   mozilla::Monitor mMonitor;
   BlobChild* mActor;
-  nsCOMPtr<nsIDOMBlob> mSlice;
+  nsRefPtr<DOMFileImpl> mSlice;
   uint64_t mStart;
   uint64_t mLength;
   nsString mContentType;
   bool mDone;
 
 public:
   SliceHelper(BlobChild* aActor)
     : mMonitor("BlobChild::RemoteBlob::SliceHelper::mMonitor")
@@ -883,59 +883,63 @@ public:
     , mStart(0)
     , mLength(0)
     , mDone(false)
   {
     // This may be created on any thread.
     MOZ_ASSERT(aActor);
   }
 
-  nsresult
+  DOMFileImpl*
   GetSlice(uint64_t aStart,
            uint64_t aLength,
            const nsAString& aContentType,
-           nsIDOMBlob** aSlice)
+           ErrorResult& aRv)
   {
     // This may be called on any thread.
-    MOZ_ASSERT(aSlice);
     MOZ_ASSERT(mActor);
     MOZ_ASSERT(!mSlice);
     MOZ_ASSERT(!mDone);
 
     mStart = aStart;
     mLength = aLength;
     mContentType = aContentType;
 
     if (NS_IsMainThread()) {
       RunInternal(false);
     }
     else {
       nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+      if (!mainThread) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
 
-      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
-      NS_ENSURE_SUCCESS(rv, rv);
+      aRv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
 
       {
         MonitorAutoLock lock(mMonitor);
         while (!mDone) {
           lock.Wait();
         }
       }
     }
 
     MOZ_ASSERT(!mActor);
     MOZ_ASSERT(mDone);
 
     if (!mSlice) {
-      return NS_ERROR_UNEXPECTED;
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
     }
 
-    mSlice.forget(aSlice);
-    return NS_OK;
+    return mSlice;
   }
 
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     RunInternal(true);
     return NS_OK;
@@ -968,17 +972,18 @@ private:
     slicedParams.end() = mStart + mLength;
     slicedParams.sourceChild() = mActor;
 
     ParentBlobConstructorParams otherSideParams;
     otherSideParams.blobParams() = slicedParams;
     otherSideParams.optionalInputStreamParams() = mozilla::void_t();
 
     if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
-      mSlice = newActor->GetBlob();
+      nsCOMPtr<nsIDOMBlob> blob = newActor->GetBlob();
+      mSlice = static_cast<DOMFile*>(blob.get())->Impl();
     }
 
     mActor = nullptr;
 
     if (aNotify) {
       MonitorAutoLock lock(mMonitor);
       mDone = true;
       lock.Notify();
@@ -988,36 +993,39 @@ private:
     }
   }
 };
 
 /*******************************************************************************
  * BlobChild::RemoteBlob Implementation
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, DOMFileImplBase, nsIRemoteBlob)
+NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, DOMFileImpl, nsIRemoteBlob)
 
 already_AddRefed<nsIDOMBlob>
 BlobChild::
 RemoteBlob::CreateSlice(uint64_t aStart,
                         uint64_t aLength,
                         const nsAString& aContentType)
 {
   if (!mActor) {
     return nullptr;
   }
 
   nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
 
-  nsCOMPtr<nsIDOMBlob> slice;
-  nsresult rv =
-    helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  ErrorResult rv;
+  nsRefPtr<DOMFileImpl> slice = helper->GetSlice(aStart, aLength,
+                                                 aContentType, rv);
+  if (rv.Failed()) {
+    return nullptr;
+  }
 
-  return slice.forget();
+  nsRefPtr<DOMFile> file = new DOMFile(slice);
+  return file.forget();
 }
 
 nsresult
 BlobChild::
 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
 {
   if (!mActor) {
     return NS_ERROR_UNEXPECTED;
@@ -1563,17 +1571,17 @@ private:
   }
 };
 
 class BlobParent::RemoteBlob::SliceHelper MOZ_FINAL
   : public nsRunnable
 {
   mozilla::Monitor mMonitor;
   BlobParent* mActor;
-  nsCOMPtr<nsIDOMBlob> mSlice;
+  nsRefPtr<DOMFileImpl> mSlice;
   uint64_t mStart;
   uint64_t mLength;
   nsString mContentType;
   bool mDone;
 
 public:
   SliceHelper(BlobParent* aActor)
     : mMonitor("BlobParent::RemoteBlob::SliceHelper::mMonitor")
@@ -1581,59 +1589,63 @@ public:
     , mStart(0)
     , mLength(0)
     , mDone(false)
   {
     // This may be created on any thread.
     MOZ_ASSERT(aActor);
   }
 
-  nsresult
+  DOMFileImpl*
   GetSlice(uint64_t aStart,
            uint64_t aLength,
            const nsAString& aContentType,
-           nsIDOMBlob** aSlice)
+           ErrorResult& aRv)
   {
     // This may be called on any thread.
-    MOZ_ASSERT(aSlice);
     MOZ_ASSERT(mActor);
     MOZ_ASSERT(!mSlice);
     MOZ_ASSERT(!mDone);
 
     mStart = aStart;
     mLength = aLength;
     mContentType = aContentType;
 
     if (NS_IsMainThread()) {
       RunInternal(false);
     }
     else {
       nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
-      NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
+      if (!mainThread) {
+        aRv.Throw(NS_ERROR_FAILURE);
+        return nullptr;
+      }
 
-      nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
-      NS_ENSURE_SUCCESS(rv, rv);
+      aRv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
+      if (aRv.Failed()) {
+        return nullptr;
+      }
 
       {
         MonitorAutoLock lock(mMonitor);
         while (!mDone) {
           lock.Wait();
         }
       }
     }
 
     MOZ_ASSERT(!mActor);
     MOZ_ASSERT(mDone);
 
     if (!mSlice) {
-      return NS_ERROR_UNEXPECTED;
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
     }
 
-    mSlice.forget(aSlice);
-    return NS_OK;
+    return mSlice;
   }
 
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     RunInternal(true);
     return NS_OK;
@@ -1668,17 +1680,18 @@ private:
     slicedParams.contentType() = mContentType;
     slicedParams.begin() = mStart;
     slicedParams.end() = mStart + mLength;
     slicedParams.sourceParent() = mActor;
 
     ChildBlobConstructorParams otherSideParams = slicedParams;
 
     if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
-      mSlice = newActor->GetBlob();
+      nsCOMPtr<nsIDOMBlob> blob =newActor->GetBlob();
+      mSlice = static_cast<DOMFile*>(blob.get())->Impl();
     }
 
     mActor = nullptr;
 
     if (aNotify) {
       MonitorAutoLock lock(mMonitor);
       mDone = true;
       lock.Notify();
@@ -1688,37 +1701,39 @@ private:
     }
   }
 };
 
 /*******************************************************************************
  * BlobChild::RemoteBlob Implementation
  ******************************************************************************/
 
-NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, DOMFileImplBase,
-                            nsIRemoteBlob)
+NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, DOMFileImpl, nsIRemoteBlob)
 
 already_AddRefed<nsIDOMBlob>
 BlobParent::
 RemoteBlob::CreateSlice(uint64_t aStart,
                         uint64_t aLength,
                         const nsAString& aContentType)
 {
   if (!mActor) {
     return nullptr;
   }
 
   nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
 
-  nsCOMPtr<nsIDOMBlob> slice;
-  nsresult rv =
-    helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
-  NS_ENSURE_SUCCESS(rv, nullptr);
+  ErrorResult rv;
+  nsRefPtr<DOMFileImpl> slice = helper->GetSlice(aStart, aLength,
+                                                 aContentType, rv);
+  if (rv.Failed()) {
+    return nullptr;
+  }
 
-  return slice.forget();
+  nsRefPtr<DOMFile> file = new DOMFile(slice);
+  return file.forget();
 }
 
 nsresult
 BlobParent::
 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
 {
   if (mInputStreamParams.type() != InputStreamParams::T__None) {
     nsTArray<FileDescriptor> fds;
--- a/dom/workers/URL.cpp
+++ b/dom/workers/URL.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "URL.h"
 
+#include "nsDOMFile.h"
 #include "nsIDocument.h"
-#include "nsIDOMFile.h"
 #include "nsIIOService.h"
 #include "nsPIDOMWindow.h"
 
 #include "mozilla/dom/URL.h"
 #include "mozilla/dom/URLBinding.h"
 #include "mozilla/dom/URLSearchParams.h"
 #include "nsGlobalWindow.h"
 #include "nsHostObjectProtocolHandler.h"
@@ -62,28 +62,28 @@ private:
 
   nsRefPtr<mozilla::dom::URL> mURL;
 };
 
 // This class creates an URL from a DOM Blob on the main thread.
 class CreateURLRunnable : public WorkerMainThreadRunnable
 {
 private:
-  nsIDOMBlob* mBlob;
+  DOMFileImpl* mBlobImpl;
   nsString& mURL;
 
 public:
-  CreateURLRunnable(WorkerPrivate* aWorkerPrivate, nsIDOMBlob* aBlob,
+  CreateURLRunnable(WorkerPrivate* aWorkerPrivate, DOMFileImpl* aBlobImpl,
                     const mozilla::dom::objectURLOptions& aOptions,
                     nsString& aURL)
   : WorkerMainThreadRunnable(aWorkerPrivate),
-    mBlob(aBlob),
+    mBlobImpl(aBlobImpl),
     mURL(aURL)
   {
-    MOZ_ASSERT(aBlob);
+    MOZ_ASSERT(aBlobImpl);
   }
 
   bool
   MainThreadRun()
   {
     AssertIsOnMainThread();
 
     nsCOMPtr<nsIPrincipal> principal;
@@ -101,17 +101,17 @@ public:
     } else {
       MOZ_ASSERT_IF(!mWorkerPrivate->GetParent(), mWorkerPrivate->IsChromeWorker());
       principal = mWorkerPrivate->GetPrincipal();
     }
 
     nsCString url;
     nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(
         NS_LITERAL_CSTRING(BLOBURI_SCHEME),
-        mBlob, principal, url);
+        mBlobImpl, principal, url);
 
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to add data entry for the blob!");
       SetDOMStringToNull(mURL);
       return false;
     }
 
     if (doc) {
@@ -852,18 +852,20 @@ URL::CreateObjectURL(const GlobalObject&
     SetDOMStringToNull(aResult);
 
     NS_NAMED_LITERAL_STRING(argStr, "Argument 1 of URL.createObjectURL");
     NS_NAMED_LITERAL_STRING(blobStr, "Blob");
     aRv.ThrowTypeError(MSG_DOES_NOT_IMPLEMENT_INTERFACE, &argStr, &blobStr);
     return;
   }
 
+  DOMFile* domBlob = static_cast<DOMFile*>(blob.get());
+
   nsRefPtr<CreateURLRunnable> runnable =
-    new CreateURLRunnable(workerPrivate, blob, aOptions, aResult);
+    new CreateURLRunnable(workerPrivate, domBlob->Impl(), aOptions, aResult);
 
   if (!runnable->Dispatch(cx)) {
     JS_ReportPendingException(cx);
   }
 }
 
 // static
 void
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -299,58 +299,54 @@ struct WorkerStructuredCloneCallbacks
   static JSObject*
   Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag,
        uint32_t aData, void* aClosure)
   {
     // See if object is a nsIDOMFile pointer.
     if (aTag == DOMWORKER_SCTAG_FILE) {
       MOZ_ASSERT(!aData);
 
-      nsIDOMFile* file;
-      if (JS_ReadBytes(aReader, &file, sizeof(file))) {
-        MOZ_ASSERT(file);
+      DOMFileImpl* fileImpl;
+      if (JS_ReadBytes(aReader, &fileImpl, sizeof(fileImpl))) {
+        MOZ_ASSERT(fileImpl);
 
 #ifdef DEBUG
         {
           // File should not be mutable.
-          nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
           bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
+          NS_ASSERTION(NS_SUCCEEDED(fileImpl->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable file should be passed to worker");
         }
 #endif
 
-        // nsIDOMFiles should be threadsafe, thus we will use the same instance
-        // in the worker.
+        nsRefPtr<DOMFile> file = new DOMFile(fileImpl);
         JSObject* jsFile = file::CreateFile(aCx, file);
         return jsFile;
       }
     }
     // See if object is a nsIDOMBlob pointer.
     else if (aTag == DOMWORKER_SCTAG_BLOB) {
       MOZ_ASSERT(!aData);
 
-      nsIDOMBlob* blob;
-      if (JS_ReadBytes(aReader, &blob, sizeof(blob))) {
-        MOZ_ASSERT(blob);
+      DOMFileImpl* blobImpl;
+      if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
+        MOZ_ASSERT(blobImpl);
 
 #ifdef DEBUG
         {
           // Blob should not be mutable.
-          nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
           bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
+          NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable blob should be passed to worker");
         }
 #endif
 
-        // nsIDOMBlob should be threadsafe, thus we will use the same instance
-        // in the worker.
+        nsRefPtr<DOMFile> blob = new DOMFile(blobImpl);
         JSObject* jsBlob = file::CreateBlob(aCx, blob);
         return jsBlob;
       }
     }
     // See if the object is an ImageData.
     else if (aTag == SCTAG_DOM_IMAGEDATA) {
       MOZ_ASSERT(!aData);
 
@@ -384,33 +380,34 @@ struct WorkerStructuredCloneCallbacks
     // We'll stash any nsISupports pointers that need to be AddRef'd here.
     nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
       static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
 
     // See if this is a File object.
     {
       nsIDOMFile* file = file::GetDOMFileFromJSObject(aObj);
       if (file) {
+        DOMFileImpl* fileImpl = static_cast<DOMFile*>(file)->Impl();
         if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FILE, 0) &&
-            JS_WriteBytes(aWriter, &file, sizeof(file))) {
-          clonedObjects->AppendElement(file);
+            JS_WriteBytes(aWriter, &fileImpl, sizeof(fileImpl))) {
+          clonedObjects->AppendElement(fileImpl);
           return true;
         }
       }
     }
 
     // See if this is a Blob object.
     {
       nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aObj);
       if (blob) {
-        nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
-        if (mutableBlob && NS_SUCCEEDED(mutableBlob->SetMutable(false)) &&
+        DOMFileImpl* blobImpl = static_cast<DOMFile*>(blob)->Impl();
+        if (blobImpl && NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
             JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
-            JS_WriteBytes(aWriter, &blob, sizeof(blob))) {
-          clonedObjects->AppendElement(blob);
+            JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
+          clonedObjects->AppendElement(blobImpl);
           return true;
         }
       }
     }
 
     // See if this is an ImageData object.
     {
       ImageData* imageData = nullptr;
@@ -456,31 +453,32 @@ struct MainThreadWorkerStructuredCloneCa
        uint32_t aData, void* aClosure)
   {
     AssertIsOnMainThread();
 
     // See if object is a nsIDOMFile pointer.
     if (aTag == DOMWORKER_SCTAG_FILE) {
       MOZ_ASSERT(!aData);
 
-      nsIDOMFile* file;
-      if (JS_ReadBytes(aReader, &file, sizeof(file))) {
-        MOZ_ASSERT(file);
+      DOMFileImpl* fileImpl;
+      if (JS_ReadBytes(aReader, &fileImpl, sizeof(fileImpl))) {
+        MOZ_ASSERT(fileImpl);
 
 #ifdef DEBUG
         {
           // File should not be mutable.
-          nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
           bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable)) &&
+          NS_ASSERTION(NS_SUCCEEDED(fileImpl->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable file should be passed to worker");
         }
 #endif
 
+        nsCOMPtr<nsIDOMFile> file = new DOMFile(fileImpl);
+
         // nsIDOMFiles should be threadsafe, thus we will use the same instance
         // on the main thread.
         JS::Rooted<JS::Value> wrappedFile(aCx);
         nsresult rv = nsContentUtils::WrapNative(aCx, file,
                                                  &NS_GET_IID(nsIDOMFile),
                                                  &wrappedFile);
         if (NS_FAILED(rv)) {
           Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
@@ -489,31 +487,32 @@ struct MainThreadWorkerStructuredCloneCa
 
         return &wrappedFile.toObject();
       }
     }
     // See if object is a nsIDOMBlob pointer.
     else if (aTag == DOMWORKER_SCTAG_BLOB) {
       MOZ_ASSERT(!aData);
 
-      nsIDOMBlob* blob;
-      if (JS_ReadBytes(aReader, &blob, sizeof(blob))) {
-        MOZ_ASSERT(blob);
+      DOMFileImpl* blobImpl;
+      if (JS_ReadBytes(aReader, &blobImpl, sizeof(blobImpl))) {
+        MOZ_ASSERT(blobImpl);
 
 #ifdef DEBUG
         {
           // Blob should not be mutable.
-          nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
           bool isMutable;
-          NS_ASSERTION(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable)) &&
+          NS_ASSERTION(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable)) &&
                        !isMutable,
                        "Only immutable blob should be passed to worker");
         }
 #endif
 
+        nsCOMPtr<nsIDOMBlob> blob = new DOMFile(blobImpl);
+
         // nsIDOMBlobs should be threadsafe, thus we will use the same instance
         // on the main thread.
         JS::Rooted<JS::Value> wrappedBlob(aCx);
         nsresult rv = nsContentUtils::WrapNative(aCx, blob,
                                                  &NS_GET_IID(nsIDOMBlob),
                                                  &wrappedBlob);
         if (NS_FAILED(rv)) {
           Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR);
@@ -545,46 +544,50 @@ struct MainThreadWorkerStructuredCloneCa
     nsContentUtils::XPConnect()->
       GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
 
     if (wrappedNative) {
       // Get the raw nsISupports out of it.
       nsISupports* wrappedObject = wrappedNative->Native();
       NS_ASSERTION(wrappedObject, "Null pointer?!");
 
-      nsISupports* ccISupports = nullptr;
-      wrappedObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
-                                    reinterpret_cast<void**>(&ccISupports));
-      if (ccISupports) {
-        NS_WARNING("Cycle collected objects are not supported!");
-      }
-      else {
-        // See if the wrapped native is a nsIDOMFile.
-        nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject);
-        if (file) {
-          nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file);
-          if (mutableFile && NS_SUCCEEDED(mutableFile->SetMutable(false))) {
-            nsIDOMFile* filePtr = file;
+      // See if the wrapped native is a nsIDOMFile.
+      nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject);
+      if (file) {
+        nsRefPtr<DOMFileImpl> fileImpl =
+          static_cast<DOMFile*>(file.get())->Impl();
+
+        if (fileImpl->IsCCed()) {
+          NS_WARNING("Cycle collected file objects are not supported!");
+        } else {
+          if (NS_SUCCEEDED(fileImpl->SetMutable(false))) {
+            DOMFileImpl* fileImplPtr = fileImpl;
             if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_FILE, 0) &&
-                JS_WriteBytes(aWriter, &filePtr, sizeof(filePtr))) {
-              clonedObjects->AppendElement(file);
+                JS_WriteBytes(aWriter, &fileImplPtr, sizeof(fileImplPtr))) {
+              clonedObjects->AppendElement(fileImpl);
               return true;
             }
           }
         }
-
-        // See if the wrapped native is a nsIDOMBlob.
-        nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
-        if (blob) {
-          nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob);
-          if (mutableBlob && NS_SUCCEEDED(mutableBlob->SetMutable(false))) {
-            nsIDOMBlob* blobPtr = blob;
+      }
+
+      // See if the wrapped native is a nsIDOMBlob.
+      nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject);
+      if (blob) {
+        nsRefPtr<DOMFileImpl> blobImpl =
+          static_cast<DOMFile*>(blob.get())->Impl();
+
+        if (blobImpl->IsCCed()) {
+          NS_WARNING("Cycle collected blob objects are not supported!");
+        } else {
+          if (NS_SUCCEEDED(blobImpl->SetMutable(false))) {
+            DOMFileImpl* blobImplPtr = blobImpl;
             if (JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
-                JS_WriteBytes(aWriter, &blobPtr, sizeof(blobPtr))) {
-              clonedObjects->AppendElement(blob);
+                JS_WriteBytes(aWriter, &blobImplPtr, sizeof(blobImplPtr))) {
+              clonedObjects->AppendElement(blobImpl);
               return true;
             }
           }
         }
       }
     }
 
     JS_ClearPendingException(aCx);