Bug 1842007 - Part 2: Replace DomPromiseListener use with Promise method in DoubleBufferQueueImpl r=dom-storage-reviewers,janv,asuth

AddCallbacksWithCycleCollectedArgs prevents potential cycle. (I'm assuming `this` and `newPage` cannot make cycle here)

Also making FileSystemDirectoryIterator::Impl as refcountable to safely capture `this`.

Differential Revision: https://phabricator.services.mozilla.com/D182940
This commit is contained in:
Kagami Sascha Rosylight 2023-09-19 09:58:00 +00:00
parent 030c922baf
commit 2cc2490039
6 changed files with 43 additions and 32 deletions

View file

@ -46,7 +46,7 @@ class FileSystemDirectoryHandle final : public FileSystemHandle {
FileSystemHandleKind Kind() const override; FileSystemHandleKind Kind() const override;
struct IteratorData { struct IteratorData {
UniquePtr<FileSystemDirectoryIterator::Impl> mImpl; RefPtr<FileSystemDirectoryIterator::Impl> mImpl;
}; };
void InitAsyncIteratorData(IteratorData& aData, void InitAsyncIteratorData(IteratorData& aData,

View file

@ -23,8 +23,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemDirectoryIterator, mGlobal);
FileSystemDirectoryIterator::FileSystemDirectoryIterator( FileSystemDirectoryIterator::FileSystemDirectoryIterator(
nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager, nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
UniquePtr<Impl> aImpl) RefPtr<Impl>& aImpl)
: mGlobal(aGlobal), mManager(aManager), mImpl(std::move(aImpl)) {} : mGlobal(aGlobal), mManager(aManager), mImpl(aImpl) {}
// WebIDL Boilerplate // WebIDL Boilerplate

View file

@ -31,9 +31,13 @@ class FileSystemDirectoryIterator : public nsISupports, public nsWrapperCache {
public: public:
class Impl { class Impl {
public: public:
NS_INLINE_DECL_REFCOUNTING(Impl)
virtual already_AddRefed<Promise> Next(nsIGlobalObject* aGlobal, virtual already_AddRefed<Promise> Next(nsIGlobalObject* aGlobal,
RefPtr<FileSystemManager>& aManager, RefPtr<FileSystemManager>& aManager,
ErrorResult& aError) = 0; ErrorResult& aError) = 0;
protected:
virtual ~Impl() = default; virtual ~Impl() = default;
}; };
@ -42,7 +46,7 @@ class FileSystemDirectoryIterator : public nsISupports, public nsWrapperCache {
explicit FileSystemDirectoryIterator(nsIGlobalObject* aGlobal, explicit FileSystemDirectoryIterator(nsIGlobalObject* aGlobal,
RefPtr<FileSystemManager>& aManager, RefPtr<FileSystemManager>& aManager,
UniquePtr<Impl> aImpl); RefPtr<Impl>& aImpl);
// WebIDL Boilerplate // WebIDL Boilerplate
nsIGlobalObject* GetParentObject() const; nsIGlobalObject* GetParentObject() const;
@ -61,7 +65,7 @@ class FileSystemDirectoryIterator : public nsISupports, public nsWrapperCache {
RefPtr<FileSystemManager> mManager; RefPtr<FileSystemManager> mManager;
private: private:
UniquePtr<Impl> mImpl; RefPtr<Impl> mImpl;
}; };
} // namespace dom } // namespace dom

View file

@ -16,6 +16,7 @@
#include "mozilla/dom/FileSystemLog.h" #include "mozilla/dom/FileSystemLog.h"
#include "mozilla/dom/FileSystemManager.h" #include "mozilla/dom/FileSystemManager.h"
#include "mozilla/dom/IterableIterator.h" #include "mozilla/dom/IterableIterator.h"
#include "mozilla/dom/Promise-inl.h"
#include "mozilla/dom/Promise.h" #include "mozilla/dom/Promise.h"
#include "mozilla/dom/PromiseNativeHandler.h" #include "mozilla/dom/PromiseNativeHandler.h"
@ -117,9 +118,9 @@ class DoubleBufferQueueImpl
return promise.forget(); return promise.forget();
} }
~DoubleBufferQueueImpl() = default;
protected: protected:
~DoubleBufferQueueImpl() override = default;
void next(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager, void next(nsIGlobalObject* aGlobal, RefPtr<FileSystemManager>& aManager,
RefPtr<Promise> aResult, ErrorResult& aError) { RefPtr<Promise> aResult, ErrorResult& aError) {
LOG_VERBOSE(("next")); LOG_VERBOSE(("next"));
@ -138,33 +139,38 @@ class DoubleBufferQueueImpl
auto newPage = MakeRefPtr<FileSystemEntryMetadataArray>(); auto newPage = MakeRefPtr<FileSystemEntryMetadataArray>();
RefPtr<DomPromiseListener> listener = new DomPromiseListener( promise->AddCallbacksWithCycleCollectedArgs(
[global = nsCOMPtr<nsIGlobalObject>(aGlobal), [self = RefPtr(this), newPage](
manager = RefPtr<FileSystemManager>(aManager), newPage, aResult, JSContext*, JS::Handle<JS::Value>, ErrorResult&,
this](JSContext* aCx, JS::Handle<JS::Value> aValue) mutable { RefPtr<FileSystemManager>& aManager, RefPtr<Promise>& aResult) {
MOZ_ASSERT(0u == mWithinPageIndex); MOZ_ASSERT(0u == self->mWithinPageIndex);
MOZ_ASSERT(newPage->Length() <= PageSize); MOZ_ASSERT(newPage->Length() <= PageSize);
const size_t startPos = mCurrentPageIsLastPage ? 0u : PageSize; const size_t startPos =
if (mData.Length() < 2 * PageSize) { self->mCurrentPageIsLastPage ? 0u : PageSize;
mData.InsertElementsAt(startPos, newPage->Elements(), if (self->mData.Length() < 2 * PageSize) {
self->mData.InsertElementsAt(startPos, newPage->Elements(),
newPage->Length()); newPage->Length());
} else { } else {
mData.ReplaceElementsAt(startPos, newPage->Length(), self->mData.ReplaceElementsAt(startPos, newPage->Length(),
newPage->Elements(), newPage->Length()); newPage->Elements(),
newPage->Length());
} }
MOZ_ASSERT(mData.Length() <= 2 * PageSize); MOZ_ASSERT(self->mData.Length() <= 2 * PageSize);
mWithinPageEnd = newPage->Length(); self->mWithinPageEnd = newPage->Length();
Maybe<DataType> value; Maybe<DataType> value;
if (0 != newPage->Length()) { if (0 != newPage->Length()) {
nextInternal(value); self->nextInternal(value);
} }
ResolveValue(global, manager, value, aResult); self->ResolveValue(aResult->GetGlobalObject(), aManager, value,
aResult);
}, },
[aResult](nsresult aRv) { aResult->MaybeReject(aRv); }); [](JSContext*, JS::Handle<JS::Value> aValue, ErrorResult&,
promise->AppendNativeHandler(listener); RefPtr<FileSystemManager>&,
RefPtr<Promise>& aResult) { aResult->MaybeReject(aValue); },
aManager, aResult);
FileSystemRequestHandler{}.GetEntries(aManager, mEntryId, mPageNumber, FileSystemRequestHandler{}.GetEntries(aManager, mEntryId, mPageNumber,
promise, newPage, aError); promise, newPage, aError);
@ -218,20 +224,21 @@ using UnderlyingQueue = DoubleBufferQueueImpl<ValueResolver<Type>>;
} // namespace } // namespace
UniquePtr<mozilla::dom::FileSystemDirectoryIterator::Impl> already_AddRefed<mozilla::dom::FileSystemDirectoryIterator::Impl>
FileSystemDirectoryIteratorFactory::Create( FileSystemDirectoryIteratorFactory::Create(
const FileSystemEntryMetadata& aMetadata, const FileSystemEntryMetadata& aMetadata,
IterableIteratorBase::IteratorType aType) { IterableIteratorBase::IteratorType aType) {
if (IterableIteratorBase::Entries == aType) { if (IterableIteratorBase::Entries == aType) {
return MakeUnique<UnderlyingQueue<IterableIteratorBase::Entries>>( return MakeAndAddRef<UnderlyingQueue<IterableIteratorBase::Entries>>(
aMetadata); aMetadata);
} }
if (IterableIteratorBase::Values == aType) { if (IterableIteratorBase::Values == aType) {
return MakeUnique<UnderlyingQueue<IterableIteratorBase::Values>>(aMetadata); return MakeAndAddRef<UnderlyingQueue<IterableIteratorBase::Values>>(
aMetadata);
} }
return MakeUnique<UnderlyingQueue<IterableIteratorBase::Keys>>(aMetadata); return MakeAndAddRef<UnderlyingQueue<IterableIteratorBase::Keys>>(aMetadata);
} }
} // namespace mozilla::dom::fs } // namespace mozilla::dom::fs

View file

@ -14,8 +14,8 @@ namespace mozilla::dom::fs {
class FileSystemEntryMetadata; class FileSystemEntryMetadata;
struct FileSystemDirectoryIteratorFactory { struct FileSystemDirectoryIteratorFactory {
static UniquePtr<mozilla::dom::FileSystemDirectoryIterator::Impl> Create( static already_AddRefed<mozilla::dom::FileSystemDirectoryIterator::Impl>
const FileSystemEntryMetadata& aMetadata, Create(const FileSystemEntryMetadata& aMetadata,
IterableIteratorBase::IteratorType aType); IterableIteratorBase::IteratorType aType);
}; };

View file

@ -89,7 +89,7 @@ TEST_F(TestFileSystemDirectoryHandle, isNextPromiseReturned) {
ASSERT_TRUE(dirHandle); ASSERT_TRUE(dirHandle);
auto mockIter = MakeUnique<MockFileSystemDirectoryIteratorImpl>(); auto mockIter = MakeRefPtr<MockFileSystemDirectoryIteratorImpl>();
IgnoredErrorResult error; IgnoredErrorResult error;
EXPECT_CALL(*mockIter, Next(_, _, _)) EXPECT_CALL(*mockIter, Next(_, _, _))
.WillOnce(::testing::Return(Promise::Create(mGlobal, error))); .WillOnce(::testing::Return(Promise::Create(mGlobal, error)));