diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index 380d86ce7b6d..b9eb1744b8b6 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -3648,13 +3648,10 @@ UpgradeSchemaFrom18_0To19_0(mozIStorageConnection* aConnection) return NS_OK; } -class NormalJSContext; - class UpgradeFileIdsFunction final : public mozIStorageFunction { RefPtr mFileManager; - nsAutoPtr mContext; public: UpgradeFileIdsFunction() @@ -8057,53 +8054,6 @@ private: DoDatabaseWork(DatabaseConnection* aConnection) override; }; -class NormalJSContext -{ - friend class nsAutoPtr; - - static const JSClass sGlobalClass; - static const uint32_t kContextHeapSize = 768 * 1024; - - JSContext* mContext; - JSObject* mGlobal; - -public: - static NormalJSContext* - Create(); - - JSContext* - Context() const - { - return mContext; - } - - JSObject* - Global() const - { - return mGlobal; - } - -protected: - NormalJSContext() - : mContext(nullptr) - , mGlobal(nullptr) - { - MOZ_COUNT_CTOR(NormalJSContext); - } - - ~NormalJSContext() - { - MOZ_COUNT_DTOR(NormalJSContext); - - if (mContext) { - JS_DestroyContext(mContext); - } - } - - bool - Init(); -}; - class CreateIndexOp::UpdateIndexDataValuesFunction final : public mozIStorageFunction { @@ -19535,13 +19485,7 @@ UpgradeFileIdsFunction::Init(nsIFile* aFMDirectory, return rv; } - nsAutoPtr context(NormalJSContext::Create()); - if (NS_WARN_IF(!context)) { - return NS_ERROR_FAILURE; - } - mFileManager.swap(fileManager); - mContext = context; return NS_OK; } @@ -19554,7 +19498,6 @@ UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments, MOZ_ASSERT(aArguments); MOZ_ASSERT(aResult); MOZ_ASSERT(mFileManager); - MOZ_ASSERT(mContext); AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", STORAGE); @@ -19576,30 +19519,10 @@ UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments, mFileManager, &cloneInfo); - JSContext* cx = mContext->Context(); - JSAutoRequest ar(cx); - JSAutoCompartment ac(cx, mContext->Global()); - - JS::Rooted clone(cx); - if (NS_WARN_IF(!IDBObjectStore::DeserializeUpgradeValue(cx, cloneInfo, - &clone))) { - return NS_ERROR_DOM_DATA_CLONE_ERR; - } - nsAutoString fileIds; - - for (uint32_t count = cloneInfo.mFiles.Length(), index = 0; - index < count; - index++) { - StructuredCloneFile& file = cloneInfo.mFiles[index]; - MOZ_ASSERT(file.mFileInfo); - - const int64_t id = file.mFileInfo->Id(); - - if (index) { - fileIds.Append(' '); - } - fileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id); + rv = IDBObjectStore::DeserializeUpgradeValueToFileIds(cloneInfo, fileIds); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NS_ERROR_DOM_DATA_CLONE_ERR; } nsCOMPtr result = new mozilla::storage::TextVariant(fileIds); @@ -25005,74 +24928,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } -static const JSClassOps sNormalJSContextGlobalClassOps = { - /* addProperty */ nullptr, - /* delProperty */ nullptr, - /* enumerate */ nullptr, - /* newEnumerate */ nullptr, - /* resolve */ nullptr, - /* mayResolve */ nullptr, - /* finalize */ nullptr, - /* call */ nullptr, - /* hasInstance */ nullptr, - /* construct */ nullptr, - /* trace */ JS_GlobalObjectTraceHook -}; - -const JSClass NormalJSContext::sGlobalClass = { - "IndexedDBTransactionThreadGlobal", - JSCLASS_GLOBAL_FLAGS, - &sNormalJSContextGlobalClassOps -}; - -bool -NormalJSContext::Init() -{ - MOZ_ASSERT(!IsOnBackgroundThread()); - - mContext = JS_NewContext(kContextHeapSize); - if (NS_WARN_IF(!mContext)) { - return false; - } - - // Let everyone know that we might be able to call JS. This alerts the - // profiler about certain possible deadlocks. - NS_GetCurrentThread()->SetCanInvokeJS(true); - - // Not setting this will cause JS_CHECK_RECURSION to report false positives. - JS_SetNativeStackQuota(mContext, 128 * sizeof(size_t) * 1024); - - if (NS_WARN_IF(!JS::InitSelfHostedCode(mContext))) { - return false; - } - - JSAutoRequest ar(mContext); - - JS::CompartmentOptions options; - mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, - JS::FireOnNewGlobalHook, options); - if (NS_WARN_IF(!mGlobal)) { - return false; - } - - return true; -} - -// static -NormalJSContext* -NormalJSContext::Create() -{ - MOZ_ASSERT(!IsOnBackgroundThread()); - - nsAutoPtr newContext(new NormalJSContext()); - - if (NS_WARN_IF(!newContext->Init())) { - return nullptr; - } - - return newContext.forget(); -} - NS_IMPL_ISUPPORTS(CreateIndexOp::UpdateIndexDataValuesFunction, mozIStorageFunction); diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 246f3bd12443..3aa745987575 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -872,6 +872,24 @@ public: JS::MutableHandle aResult) { MOZ_ASSERT(aCx); + + // If we have eBlob, we are in an IDB SQLite schema upgrade where we don't + // care about a real 'MutableFile', but we just care of having a propert + // |mType| flag. + if (aFile.mType == StructuredCloneFile::eBlob) { + aFile.mType = StructuredCloneFile::eMutableFile; + + // Just make a dummy object. + JS::Rooted obj(aCx, JS_NewPlainObject(aCx)); + + if (NS_WARN_IF(!obj)) { + return false; + } + + aResult.set(obj); + return true; + } + MOZ_ASSERT(aFile.mType == StructuredCloneFile::eMutableFile); if (!aFile.mMutableFile || !NS_IsMainThread()) { @@ -1009,74 +1027,6 @@ public: } }; -// We don't need to upgrade database on B2G. See the comment in ActorsParent.cpp, -// UpgradeSchemaFrom18_0To19_0() -class UpgradeDeserializationHelper -{ -public: - static bool - CreateAndWrapMutableFile(JSContext* aCx, - StructuredCloneFile& aFile, - const MutableFileData& aData, - JS::MutableHandle aResult) - { - MOZ_ASSERT(aCx); - MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob); - - aFile.mType = StructuredCloneFile::eMutableFile; - - // Just make a dummy object. The file_ids upgrade function is only - // interested in the |mType| flag. - JS::Rooted obj(aCx, JS_NewPlainObject(aCx)); - - if (NS_WARN_IF(!obj)) { - return false; - } - - aResult.set(obj); - return true; - } - - static bool - CreateAndWrapBlobOrFile(JSContext* aCx, - IDBDatabase* aDatabase, - StructuredCloneFile& aFile, - const BlobOrFileData& aData, - JS::MutableHandle aResult) - { - MOZ_ASSERT(aCx); - MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob); - MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE || - aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || - aData.tag == SCTAG_DOM_BLOB); - - // Just make a dummy object. The file_ids upgrade function is only interested - // in the |mType| flag. - JS::Rooted obj(aCx, JS_NewPlainObject(aCx)); - - if (NS_WARN_IF(!obj)) { - return false; - } - - aResult.set(obj); - return true; - } - - static bool - CreateAndWrapWasmModule(JSContext* aCx, - StructuredCloneFile& aFile, - const WasmModuleData& aData, - JS::MutableHandle aResult) - { - MOZ_ASSERT(aCx); - MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob); - - MOZ_ASSERT(false, "This should never be possible!"); - - return false; - } -}; - template JSObject* CommonStructuredCloneReadCallback(JSContext* aCx, @@ -1569,6 +1519,130 @@ private: nsresult mStatus; }; +class DeserializeUpgradeValueHelper final : public Runnable +{ +public: + explicit DeserializeUpgradeValueHelper(StructuredCloneReadInfo& aCloneReadInfo) + : Runnable("DeserializeUpgradeValueHelper") + , mMonitor("DeserializeUpgradeValueHelper::mMonitor") + , mCloneReadInfo(aCloneReadInfo) + , mStatus(NS_ERROR_FAILURE) + {} + + nsresult + DispatchAndWait(nsAString& aFileIds) + { + // We don't need to go to the main-thread and use the sandbox. + if (!mCloneReadInfo.mData.Size()) { + PopulateFileIds(aFileIds); + return NS_OK; + } + + // The operation will continue on the main-thread. + + MOZ_ASSERT(!(mCloneReadInfo.mData.Size() % sizeof(uint64_t))); + + MonitorAutoLock lock(mMonitor); + + RefPtr self = this; + nsresult rv = SystemGroup::Dispatch(TaskCategory::Other, self.forget()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + lock.Wait(); + + if (NS_FAILED(mStatus)) { + return mStatus; + } + + PopulateFileIds(aFileIds); + return NS_OK; + } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(NS_IsMainThread()); + + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + + JS::Rooted global(cx, SandboxHolder::GetSandbox(cx)); + if (NS_WARN_IF(!global)) { + OperationCompleted(NS_ERROR_FAILURE); + return NS_OK; + } + + JSAutoCompartment ac(cx, global); + + JS::Rooted value(cx); + nsresult rv = DeserializeUpgradeValue(cx, &value); + if (NS_WARN_IF(NS_FAILED(rv))) { + OperationCompleted(rv); + return NS_OK; + } + + OperationCompleted(NS_OK); + return NS_OK; + } + +private: + nsresult + DeserializeUpgradeValue(JSContext* aCx, JS::MutableHandle aValue) + { + static const JSStructuredCloneCallbacks callbacks = { + CommonStructuredCloneReadCallback, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + }; + + if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData, + JS_STRUCTURED_CLONE_VERSION, + JS::StructuredCloneScope::SameProcessSameThread, + aValue, &callbacks, &mCloneReadInfo)) { + return NS_ERROR_DOM_DATA_CLONE_ERR; + } + + return NS_OK; + } + + void + PopulateFileIds(nsAString& aFileIds) + { + for (uint32_t count = mCloneReadInfo.mFiles.Length(), index = 0; + index < count; + index++) { + StructuredCloneFile& file = mCloneReadInfo.mFiles[index]; + MOZ_ASSERT(file.mFileInfo); + + const int64_t id = file.mFileInfo->Id(); + + if (index) { + aFileIds.Append(' '); + } + aFileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id); + } + } + + void + OperationCompleted(nsresult aStatus) + { + mStatus = aStatus; + + MonitorAutoLock lock(mMonitor); + lock.Notify(); + } + + Monitor mMonitor; + StructuredCloneReadInfo& mCloneReadInfo; + nsresult mStatus; +}; + } // anonymous // static @@ -1590,39 +1664,15 @@ IDBObjectStore::DeserializeIndexValueToUpdateInfos(int64_t aIndexID, } // static -bool -IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx, - StructuredCloneReadInfo& aCloneReadInfo, - JS::MutableHandle aValue) +nsresult +IDBObjectStore::DeserializeUpgradeValueToFileIds(StructuredCloneReadInfo& aCloneReadInfo, + nsAString& aFileIds) { MOZ_ASSERT(!NS_IsMainThread()); - MOZ_ASSERT(aCx); - if (!aCloneReadInfo.mData.Size()) { - aValue.setUndefined(); - return true; - } - - MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t))); - - JSAutoRequest ar(aCx); - - static JSStructuredCloneCallbacks callbacks = { - CommonStructuredCloneReadCallback, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - }; - - if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION, - JS::StructuredCloneScope::SameProcessSameThread, - aValue, &callbacks, &aCloneReadInfo)) { - return false; - } - - return true; + RefPtr helper = + new DeserializeUpgradeValueHelper(aCloneReadInfo); + return helper->DispatchAndWait(aFileIds); } #ifdef DEBUG diff --git a/dom/indexedDB/IDBObjectStore.h b/dom/indexedDB/IDBObjectStore.h index 272d4b4aa4e5..7f0ef132fdd9 100644 --- a/dom/indexedDB/IDBObjectStore.h +++ b/dom/indexedDB/IDBObjectStore.h @@ -105,10 +105,9 @@ public: StructuredCloneReadInfo& aCloneReadInfo, JS::MutableHandle aValue); - static bool - DeserializeUpgradeValue(JSContext* aCx, - StructuredCloneReadInfo& aCloneReadInfo, - JS::MutableHandle aValue); + static nsresult + DeserializeUpgradeValueToFileIds(StructuredCloneReadInfo& aCloneReadInfo, + nsAString& aFileIds); static const JSClass* DummyPropClass()