Bug 1113062 - IndexedDB FileSnapshot not CCed. r=janv, a=sledru
authorAndrea Marchesini <amarchesini@mozilla.com>
Sun, 11 Jan 2015 21:35:24 +0000
changeset 242853 962ac9efa80c
parent 242852 f203230f49f4
child 242854 e16f64387888
push id4321
push userryanvm@gmail.com
push date2015-01-14 15:04 +0000
treeherdermozilla-beta@a78eb4dd84f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjanv, sledru
bugs1113062
milestone36.0
Bug 1113062 - IndexedDB FileSnapshot not CCed. r=janv, a=sledru
dom/base/File.cpp
dom/base/File.h
dom/base/MultipartFileImpl.cpp
dom/base/MultipartFileImpl.h
dom/indexedDB/FileSnapshot.cpp
dom/indexedDB/FileSnapshot.h
dom/indexedDB/IDBFileHandle.cpp
dom/indexedDB/IDBFileHandle.h
dom/ipc/Blob.cpp
dom/workers/WorkerPrivate.cpp
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -124,25 +124,24 @@ nsresult DataOwnerAdapter::Create(DataOw
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // mozilla::dom::File implementation
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(File)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(File)
-  MOZ_ASSERT(tmp->mImpl);
-  tmp->mImpl->Unlink();
+  // No unlink for mImpl bacause FileImpl is not CC-able.
+  tmp->mImpl = nullptr;
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(File)
-  MOZ_ASSERT(tmp->mImpl);
-  tmp->mImpl->Traverse(cb);
+  // No traverse for mImpl bacause FileImpl is not CC-able.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(File)
   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -210,17 +210,17 @@ public:
 
 private:
   ~File() {};
 
   // The member is the real backend implementation of this File/Blob.
   // 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<FileImpl> mImpl;
+  nsRefPtr<FileImpl> mImpl;
 
   nsCOMPtr<nsISupports> mParent;
 };
 
 // This is the abstract class for any File backend. It must be nsISupports
 // because this class must be ref-counted and it has to work with IPC.
 class FileImpl : public nsISupports
 {
@@ -281,23 +281,20 @@ public:
   virtual bool IsMemoryFile() const = 0;
 
   virtual bool IsSizeUnknown() const = 0;
 
   virtual bool IsDateUnknown() const = 0;
 
   virtual bool IsFile() const = 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
+  // True if this implementation can be sent to other threads.
+  virtual bool MayBeClonedToOtherThreads() const
   {
-    return false;
+    return true;
   }
 
 protected:
   virtual ~FileImpl() {}
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(FileImpl, FILEIMPL_IID)
 
@@ -455,19 +452,16 @@ public:
     return false;
   }
 
   virtual bool IsSizeUnknown() const
   {
     return mLength == UINT64_MAX;
   }
 
-  virtual void Unlink() {}
-  virtual void Traverse(nsCycleCollectionTraversalCallback &aCb) {}
-
 protected:
   virtual ~FileImplBase() {}
 
   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!");
 
--- a/dom/base/MultipartFileImpl.cpp
+++ b/dom/base/MultipartFileImpl.cpp
@@ -347,8 +347,20 @@ MultipartFileImpl::InitializeChromeFile(
   nsCOMPtr<nsIFile> file;
   aRv = NS_NewLocalFile(aData, false, getter_AddRefs(file));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
   InitializeChromeFile(aWindow, file, aBag, false, aRv);
 }
+
+bool
+MultipartFileImpl::MayBeClonedToOtherThreads() const
+{
+  for (uint32_t i = 0; i < mBlobImpls.Length(); ++i) {
+    if (!mBlobImpls[i]->MayBeClonedToOtherThreads()) {
+      return false;
+    }
+  }
+
+  return true;
+}
--- a/dom/base/MultipartFileImpl.h
+++ b/dom/base/MultipartFileImpl.h
@@ -106,16 +106,18 @@ public:
     mName = aName;
   }
 
   void SetFromNsIFile(bool aValue)
   {
     mIsFromNsIFile = aValue;
   }
 
+  virtual bool MayBeClonedToOtherThreads() const MOZ_OVERRIDE;
+
 protected:
   virtual ~MultipartFileImpl() {}
 
   void SetLengthAndModifiedDate();
 
   nsTArray<nsRefPtr<FileImpl>> mBlobImpls;
   bool mIsFromNsIFile;
 };
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -26,28 +26,30 @@ FileImplSnapshot::FileImplSnapshot(const
                                    nsIFile* aFile,
                                    IDBFileHandle* aFileHandle,
                                    FileInfo* aFileInfo)
   : FileImplBase(aName,
                  aContentType,
                  aMetadataParams->Size(),
                  aMetadataParams->LastModified())
   , mFile(aFile)
-  , mFileHandle(aFileHandle)
   , mWholeFile(true)
 {
   AssertSanity();
   MOZ_ASSERT(aMetadataParams);
   MOZ_ASSERT(aMetadataParams->Size() != UINT64_MAX);
   MOZ_ASSERT(aMetadataParams->LastModified() != INT64_MAX);
   MOZ_ASSERT(aFile);
   MOZ_ASSERT(aFileHandle);
   MOZ_ASSERT(aFileInfo);
 
   mFileInfos.AppendElement(aFileInfo);
+
+  mFileHandle =
+    do_GetWeakReference(NS_ISUPPORTS_CAST(EventTarget*, aFileHandle));
 }
 
 // Create slice
 FileImplSnapshot::FileImplSnapshot(const FileImplSnapshot* aOther,
                                    uint64_t aStart,
                                    uint64_t aLength,
                                    const nsAString& aContentType)
   : FileImplBase(aContentType, aOther->mStart + aStart, aLength)
@@ -83,49 +85,29 @@ FileImplSnapshot::AssertSanity()
   MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 #endif // DEBUG
 
 NS_IMPL_ISUPPORTS_INHERITED(FileImplSnapshot, FileImpl, PIFileImplSnapshot)
 
-void
-FileImplSnapshot::Unlink()
-{
-  AssertSanity();
-
-  FileImplSnapshot* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileHandle);
-}
-
-void
-FileImplSnapshot::Traverse(nsCycleCollectionTraversalCallback &cb)
-{
-  AssertSanity();
-
-  FileImplSnapshot* tmp = this;
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileHandle);
-}
-
-bool
-FileImplSnapshot::IsCCed() const
-{
-  AssertSanity();
-
-  return true;
-}
-
 nsresult
 FileImplSnapshot::GetInternalStream(nsIInputStream** aStream)
 {
   AssertSanity();
 
-  nsresult rv = mFileHandle->OpenInputStream(mWholeFile, mStart, mLength,
-                                             aStream);
+  nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
+  nsRefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
+  if (!fileHandle) {
+    return NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR;
+  }
+
+  nsresult rv = fileHandle->OpenInputStream(mWholeFile, mStart, mLength,
+                                            aStream);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
 already_AddRefed<FileImpl>
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_indexeddb_filesnapshot_h__
 #define mozilla_dom_indexeddb_filesnapshot_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/File.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsISupports.h"
+#include "nsWeakPtr.h"
 
 #define FILEIMPLSNAPSHOT_IID \
   {0x0dfc11b1, 0x75d3, 0x473b, {0x8c, 0x67, 0xb7, 0x23, 0xf4, 0x67, 0xd6, 0x73}}
 
 class PIFileImplSnapshot : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(FILEIMPLSNAPSHOT_IID)
@@ -35,17 +36,17 @@ class IDBFileHandle;
 
 class FileImplSnapshot MOZ_FINAL
   : public FileImplBase
   , public PIFileImplSnapshot
 {
   typedef mozilla::dom::MetadataParameters MetadataParameters;
 
   nsCOMPtr<nsIFile> mFile;
-  nsRefPtr<IDBFileHandle> mFileHandle;
+  nsWeakPtr mFileHandle;
 
   bool mWholeFile;
 
 public:
   // Create as a stored file
   FileImplSnapshot(const nsAString& aName,
                    const nsAString& aContentType,
                    MetadataParameters* aMetadataParams,
@@ -73,24 +74,20 @@ private:
 #endif
 
   virtual void
   GetMozFullPathInternal(nsAString& aFullPath, ErrorResult& aRv) 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;
+  virtual bool MayBeClonedToOtherThreads() const MOZ_OVERRIDE
+  {
+    return false;
+  }
 
   virtual already_AddRefed<FileImpl>
   CreateSlice(uint64_t aStart,
               uint64_t aLength,
               const nsAString& aContentType,
               ErrorResult& aRv) MOZ_OVERRIDE;
 
   virtual bool
--- a/dom/indexedDB/IDBFileHandle.cpp
+++ b/dom/indexedDB/IDBFileHandle.cpp
@@ -82,16 +82,17 @@ IDBFileHandle::MutableFile() const
   return mMutableFile;
 }
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(IDBFileHandle, DOMEventTargetHelper,
                                    mMutableFile)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBFileHandle)
   NS_INTERFACE_MAP_ENTRY(nsIRunnable)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 
 nsresult
 IDBFileHandle::PreHandleEvent(EventChainPreVisitor& aVisitor)
 {
--- a/dom/indexedDB/IDBFileHandle.h
+++ b/dom/indexedDB/IDBFileHandle.h
@@ -10,31 +10,33 @@
 #include "IDBFileRequest.h"
 #include "js/TypeDecls.h"
 #include "MainThreadUtils.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/FileHandle.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsWeakReference.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 struct IDBFileMetadataParameters;
 
 namespace indexedDB {
 
 class IDBMutableFile;
 
 class IDBFileHandle MOZ_FINAL : public DOMEventTargetHelper,
                                 public nsIRunnable,
-                                public FileHandleBase
+                                public FileHandleBase,
+                                public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIRUNNABLE
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBFileHandle, DOMEventTargetHelper)
 
   static already_AddRefed<IDBFileHandle>
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -1821,21 +1821,18 @@ public:
   IsSizeUnknown() const MOZ_OVERRIDE;
 
   virtual bool
   IsDateUnknown() const MOZ_OVERRIDE;
 
   virtual bool
   IsFile() const MOZ_OVERRIDE;
 
-  virtual void
-  Unlink() MOZ_OVERRIDE;
-
-  virtual void
-  Traverse(nsCycleCollectionTraversalCallback& aCallback) MOZ_OVERRIDE;
+  virtual bool
+  MayBeClonedToOtherThreads() const MOZ_OVERRIDE;
 
   virtual BlobChild*
   GetBlobChild() MOZ_OVERRIDE;
 
   virtual BlobParent*
   GetBlobParent() MOZ_OVERRIDE;
 
 private:
@@ -2527,28 +2524,21 @@ RemoteBlobImpl::IsDateUnknown() const
 
 bool
 BlobParent::
 RemoteBlobImpl::IsFile() const
 {
   return mBlobImpl->IsFile();
 }
 
-void
+bool
 BlobParent::
-RemoteBlobImpl::Unlink()
+RemoteBlobImpl::MayBeClonedToOtherThreads() const
 {
-  return mBlobImpl->Unlink();
-}
-
-void
-BlobParent::
-RemoteBlobImpl::Traverse(nsCycleCollectionTraversalCallback& aCallback)
-{
-  return mBlobImpl->Traverse(aCallback);
+  return mBlobImpl->MayBeClonedToOtherThreads();
 }
 
 BlobChild*
 BlobParent::
 RemoteBlobImpl::GetBlobChild()
 {
   return nullptr;
 }
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -451,18 +451,18 @@ struct MainThreadWorkerStructuredCloneCa
     nsTArray<nsCOMPtr<nsISupports> >* clonedObjects =
       static_cast<nsTArray<nsCOMPtr<nsISupports> >*>(aClosure);
 
     // See if this is a Blob/File object.
     {
       File* blob = nullptr;
       if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) {
         FileImpl* blobImpl = blob->Impl();
-        if (blobImpl->IsCCed()) {
-          NS_WARNING("Cycle collected blob objects are not supported!");
+        if (!blobImpl->MayBeClonedToOtherThreads()) {
+          NS_WARNING("Not all the blob implementations can be sent between threads.");
         } else if (NS_SUCCEEDED(blobImpl->SetMutable(false)) &&
                    JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0) &&
                    JS_WriteBytes(aWriter, &blobImpl, sizeof(blobImpl))) {
           clonedObjects->AppendElement(blobImpl);
           return true;
         }
       }
     }