LCOV - code coverage report
Current view: top level - dom/indexedDB - IDBObjectStore.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1055 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 69 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "IDBObjectStore.h"
       8             : 
       9             : #include "FileInfo.h"
      10             : #include "IDBCursor.h"
      11             : #include "IDBDatabase.h"
      12             : #include "IDBEvents.h"
      13             : #include "IDBFactory.h"
      14             : #include "IDBIndex.h"
      15             : #include "IDBKeyRange.h"
      16             : #include "IDBMutableFile.h"
      17             : #include "IDBRequest.h"
      18             : #include "IDBTransaction.h"
      19             : #include "IndexedDatabase.h"
      20             : #include "IndexedDatabaseInlines.h"
      21             : #include "IndexedDatabaseManager.h"
      22             : #include "js/Class.h"
      23             : #include "js/Date.h"
      24             : #include "js/StructuredClone.h"
      25             : #include "KeyPath.h"
      26             : #include "mozilla/EndianUtils.h"
      27             : #include "mozilla/ErrorResult.h"
      28             : #include "mozilla/Move.h"
      29             : #include "mozilla/dom/BindingUtils.h"
      30             : #include "mozilla/dom/ContentChild.h"
      31             : #include "mozilla/dom/ContentParent.h"
      32             : #include "mozilla/dom/DOMStringList.h"
      33             : #include "mozilla/dom/File.h"
      34             : #include "mozilla/dom/IDBMutableFileBinding.h"
      35             : #include "mozilla/dom/BlobBinding.h"
      36             : #include "mozilla/dom/IDBObjectStoreBinding.h"
      37             : #include "mozilla/dom/MemoryBlobImpl.h"
      38             : #include "mozilla/dom/StructuredCloneHolder.h"
      39             : #include "mozilla/dom/StructuredCloneTags.h"
      40             : #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
      41             : #include "mozilla/ipc/BackgroundChild.h"
      42             : #include "mozilla/ipc/PBackgroundSharedTypes.h"
      43             : #include "nsCOMPtr.h"
      44             : #include "nsQueryObject.h"
      45             : #include "ProfilerHelpers.h"
      46             : #include "ReportInternalError.h"
      47             : #include "WorkerPrivate.h"
      48             : #include "WorkerScope.h"
      49             : 
      50             : // Include this last to avoid path problems on Windows.
      51             : #include "ActorsChild.h"
      52             : 
      53             : namespace mozilla {
      54             : namespace dom {
      55             : 
      56             : using namespace mozilla::dom::indexedDB;
      57             : using namespace mozilla::dom::quota;
      58             : using namespace mozilla::dom::workers;
      59             : using namespace mozilla::ipc;
      60             : 
      61             : struct IDBObjectStore::StructuredCloneWriteInfo
      62             : {
      63             :   JSAutoStructuredCloneBuffer mCloneBuffer;
      64             :   nsTArray<StructuredCloneFile> mFiles;
      65             :   IDBDatabase* mDatabase;
      66             :   uint64_t mOffsetToKeyProp;
      67             : 
      68           0 :   explicit StructuredCloneWriteInfo(IDBDatabase* aDatabase)
      69           0 :     : mCloneBuffer(JS::StructuredCloneScope::SameProcessSameThread, nullptr,
      70             :                    nullptr)
      71             :     , mDatabase(aDatabase)
      72           0 :     , mOffsetToKeyProp(0)
      73             :   {
      74           0 :     MOZ_ASSERT(aDatabase);
      75             : 
      76           0 :     MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
      77           0 :   }
      78             : 
      79             :   StructuredCloneWriteInfo(StructuredCloneWriteInfo&& aCloneWriteInfo)
      80             :     : mCloneBuffer(Move(aCloneWriteInfo.mCloneBuffer))
      81             :     , mDatabase(aCloneWriteInfo.mDatabase)
      82             :     , mOffsetToKeyProp(aCloneWriteInfo.mOffsetToKeyProp)
      83             :   {
      84             :     MOZ_ASSERT(mDatabase);
      85             : 
      86             :     MOZ_COUNT_CTOR(StructuredCloneWriteInfo);
      87             : 
      88             :     mFiles.SwapElements(aCloneWriteInfo.mFiles);
      89             :     aCloneWriteInfo.mOffsetToKeyProp = 0;
      90             :   }
      91             : 
      92           0 :   ~StructuredCloneWriteInfo()
      93           0 :   {
      94           0 :     MOZ_COUNT_DTOR(StructuredCloneWriteInfo);
      95           0 :   }
      96             : };
      97             : 
      98             : namespace {
      99             : 
     100             : struct MOZ_STACK_CLASS MutableFileData final
     101             : {
     102             :   nsString type;
     103             :   nsString name;
     104             : 
     105           0 :   MutableFileData()
     106           0 :   {
     107           0 :     MOZ_COUNT_CTOR(MutableFileData);
     108           0 :   }
     109             : 
     110           0 :   ~MutableFileData()
     111           0 :   {
     112           0 :     MOZ_COUNT_DTOR(MutableFileData);
     113           0 :   }
     114             : };
     115             : 
     116             : struct MOZ_STACK_CLASS BlobOrFileData final
     117             : {
     118             :   uint32_t tag;
     119             :   uint64_t size;
     120             :   nsString type;
     121             :   nsString name;
     122             :   int64_t lastModifiedDate;
     123             : 
     124           0 :   BlobOrFileData()
     125           0 :     : tag(0)
     126             :     , size(0)
     127           0 :     , lastModifiedDate(INT64_MAX)
     128             :   {
     129           0 :     MOZ_COUNT_CTOR(BlobOrFileData);
     130           0 :   }
     131             : 
     132           0 :   ~BlobOrFileData()
     133           0 :   {
     134           0 :     MOZ_COUNT_DTOR(BlobOrFileData);
     135           0 :   }
     136             : };
     137             : 
     138             : struct MOZ_STACK_CLASS WasmModuleData final
     139             : {
     140             :   uint32_t bytecodeIndex;
     141             :   uint32_t compiledIndex;
     142             :   uint32_t flags;
     143             : 
     144           0 :   explicit WasmModuleData(uint32_t aFlags)
     145           0 :     : bytecodeIndex(0)
     146             :     , compiledIndex(0)
     147           0 :     , flags(aFlags)
     148             :   {
     149           0 :     MOZ_COUNT_CTOR(WasmModuleData);
     150           0 :   }
     151             : 
     152           0 :   ~WasmModuleData()
     153           0 :   {
     154           0 :     MOZ_COUNT_DTOR(WasmModuleData);
     155           0 :   }
     156             : };
     157             : 
     158             : struct MOZ_STACK_CLASS GetAddInfoClosure final
     159             : {
     160             :   IDBObjectStore::StructuredCloneWriteInfo& mCloneWriteInfo;
     161             :   JS::Handle<JS::Value> mValue;
     162             : 
     163           0 :   GetAddInfoClosure(IDBObjectStore::StructuredCloneWriteInfo& aCloneWriteInfo,
     164             :                     JS::Handle<JS::Value> aValue)
     165           0 :     : mCloneWriteInfo(aCloneWriteInfo)
     166           0 :     , mValue(aValue)
     167             :   {
     168           0 :     MOZ_COUNT_CTOR(GetAddInfoClosure);
     169           0 :   }
     170             : 
     171           0 :   ~GetAddInfoClosure()
     172           0 :   {
     173           0 :     MOZ_COUNT_DTOR(GetAddInfoClosure);
     174           0 :   }
     175             : };
     176             : 
     177             : already_AddRefed<IDBRequest>
     178           0 : GenerateRequest(JSContext* aCx, IDBObjectStore* aObjectStore)
     179             : {
     180           0 :   MOZ_ASSERT(aObjectStore);
     181           0 :   aObjectStore->AssertIsOnOwningThread();
     182             : 
     183           0 :   IDBTransaction* transaction = aObjectStore->Transaction();
     184             : 
     185             :   RefPtr<IDBRequest> request =
     186           0 :     IDBRequest::Create(aCx, aObjectStore, transaction->Database(), transaction);
     187           0 :   MOZ_ASSERT(request);
     188             : 
     189           0 :   return request.forget();
     190             : }
     191             : 
     192             : bool
     193           0 : StructuredCloneWriteCallback(JSContext* aCx,
     194             :                              JSStructuredCloneWriter* aWriter,
     195             :                              JS::Handle<JSObject*> aObj,
     196             :                              void* aClosure)
     197             : {
     198           0 :   MOZ_ASSERT(aCx);
     199           0 :   MOZ_ASSERT(aWriter);
     200           0 :   MOZ_ASSERT(aClosure);
     201             : 
     202             :   auto* cloneWriteInfo =
     203           0 :     static_cast<IDBObjectStore::StructuredCloneWriteInfo*>(aClosure);
     204             : 
     205           0 :   if (JS_GetClass(aObj) == IDBObjectStore::DummyPropClass()) {
     206           0 :     MOZ_ASSERT(!cloneWriteInfo->mOffsetToKeyProp);
     207           0 :     cloneWriteInfo->mOffsetToKeyProp = js::GetSCOffset(aWriter);
     208             : 
     209           0 :     uint64_t value = 0;
     210             :     // Omit endian swap
     211           0 :     return JS_WriteBytes(aWriter, &value, sizeof(value));
     212             :   }
     213             : 
     214             :   // UNWRAP_OBJECT calls might mutate this.
     215           0 :   JS::Rooted<JSObject*> obj(aCx, aObj);
     216             : 
     217             :   IDBMutableFile* mutableFile;
     218           0 :   if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile, &obj, mutableFile))) {
     219           0 :     if (cloneWriteInfo->mDatabase->IsFileHandleDisabled()) {
     220           0 :       return false;
     221             :     }
     222             : 
     223           0 :     IDBDatabase* database = mutableFile->Database();
     224           0 :     MOZ_ASSERT(database);
     225             : 
     226             :     // Throw when trying to store IDBMutableFile objects that live in a
     227             :     // different database.
     228           0 :     if (database != cloneWriteInfo->mDatabase) {
     229           0 :       MOZ_ASSERT(!SameCOMIdentity(database, cloneWriteInfo->mDatabase));
     230             : 
     231           0 :       if (database->Name() != cloneWriteInfo->mDatabase->Name()) {
     232           0 :         return false;
     233             :       }
     234             : 
     235           0 :       nsCString fileOrigin, databaseOrigin;
     236             :       PersistenceType filePersistenceType, databasePersistenceType;
     237             : 
     238           0 :       if (NS_WARN_IF(NS_FAILED(database->GetQuotaInfo(fileOrigin,
     239             :                                                       &filePersistenceType)))) {
     240           0 :         return false;
     241             :       }
     242             : 
     243           0 :       if (NS_WARN_IF(NS_FAILED(cloneWriteInfo->mDatabase->GetQuotaInfo(
     244             :                                                   databaseOrigin,
     245             :                                                   &databasePersistenceType)))) {
     246           0 :         return false;
     247             :       }
     248             : 
     249           0 :       if (filePersistenceType != databasePersistenceType ||
     250           0 :           fileOrigin != databaseOrigin) {
     251           0 :         return false;
     252             :       }
     253             :     }
     254             : 
     255           0 :     if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
     256           0 :       MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
     257             :       return false;
     258             :     }
     259             : 
     260           0 :     const uint32_t index = cloneWriteInfo->mFiles.Length();
     261             : 
     262           0 :     NS_ConvertUTF16toUTF8 convType(mutableFile->Type());
     263             :     uint32_t convTypeLength =
     264           0 :       NativeEndian::swapToLittleEndian(convType.Length());
     265             : 
     266           0 :     NS_ConvertUTF16toUTF8 convName(mutableFile->Name());
     267             :     uint32_t convNameLength =
     268           0 :       NativeEndian::swapToLittleEndian(convName.Length());
     269             : 
     270           0 :     if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_MUTABLEFILE, uint32_t(index)) ||
     271           0 :         !JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) ||
     272           0 :         !JS_WriteBytes(aWriter, convType.get(), convType.Length()) ||
     273           0 :         !JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) ||
     274           0 :         !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
     275           0 :       return false;
     276             :     }
     277             : 
     278           0 :     StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
     279           0 :     newFile->mMutableFile = mutableFile;
     280           0 :     newFile->mType = StructuredCloneFile::eMutableFile;
     281             : 
     282           0 :     return true;
     283             :   }
     284             : 
     285             :   {
     286           0 :     Blob* blob = nullptr;
     287           0 :     if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
     288           0 :       ErrorResult rv;
     289           0 :       uint64_t size = blob->GetSize(rv);
     290           0 :       MOZ_ASSERT(!rv.Failed());
     291             : 
     292           0 :       size = NativeEndian::swapToLittleEndian(size);
     293             : 
     294           0 :       nsString type;
     295           0 :       blob->GetType(type);
     296             : 
     297           0 :       NS_ConvertUTF16toUTF8 convType(type);
     298             :       uint32_t convTypeLength =
     299           0 :         NativeEndian::swapToLittleEndian(convType.Length());
     300             : 
     301           0 :       if (cloneWriteInfo->mFiles.Length() > size_t(UINT32_MAX)) {
     302           0 :         MOZ_ASSERT(false,
     303             :                    "Fix the structured clone data to use a bigger type!");
     304             :         return false;
     305             :       }
     306             : 
     307           0 :       const uint32_t index = cloneWriteInfo->mFiles.Length();
     308             : 
     309           0 :       if (!JS_WriteUint32Pair(aWriter,
     310           0 :                               blob->IsFile() ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
     311           0 :                               index) ||
     312           0 :           !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
     313           0 :           !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
     314           0 :           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
     315           0 :         return false;
     316             :       }
     317             : 
     318           0 :       RefPtr<File> file = blob->ToFile();
     319           0 :       if (file) {
     320           0 :         ErrorResult rv;
     321           0 :         int64_t lastModifiedDate = file->GetLastModified(rv);
     322           0 :         MOZ_ALWAYS_TRUE(!rv.Failed());
     323             : 
     324           0 :         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
     325             : 
     326           0 :         nsString name;
     327           0 :         file->GetName(name);
     328             : 
     329           0 :         NS_ConvertUTF16toUTF8 convName(name);
     330             :         uint32_t convNameLength =
     331           0 :           NativeEndian::swapToLittleEndian(convName.Length());
     332             : 
     333           0 :         if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) ||
     334           0 :             !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
     335           0 :             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
     336           0 :           return false;
     337             :         }
     338             :       }
     339             : 
     340           0 :       StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
     341           0 :       newFile->mBlob = blob;
     342           0 :       newFile->mType = StructuredCloneFile::eBlob;
     343             : 
     344           0 :       return true;
     345             :     }
     346             :   }
     347             : 
     348           0 :   if (JS::IsWasmModuleObject(aObj)) {
     349           0 :     RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
     350           0 :     MOZ_ASSERT(module);
     351             : 
     352             :     size_t bytecodeSize;
     353             :     size_t compiledSize;
     354           0 :     module->serializedSize(&bytecodeSize, &compiledSize);
     355             : 
     356           0 :     UniquePtr<uint8_t[]> bytecode(new uint8_t[bytecodeSize]);
     357           0 :     MOZ_ASSERT(bytecode);
     358             : 
     359           0 :     UniquePtr<uint8_t[]> compiled(new uint8_t[compiledSize]);
     360           0 :     MOZ_ASSERT(compiled);
     361             : 
     362           0 :     module->serialize(bytecode.get(),
     363             :                       bytecodeSize,
     364             :                       compiled.get(),
     365           0 :                       compiledSize);
     366             : 
     367             :     RefPtr<BlobImpl> blobImpl =
     368           0 :       new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
     369           0 :     RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
     370             : 
     371             :     blobImpl =
     372           0 :       new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
     373           0 :     RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
     374             : 
     375           0 :     if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
     376           0 :       MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
     377             :       return false;
     378             :     }
     379             : 
     380           0 :     const uint32_t index = cloneWriteInfo->mFiles.Length();
     381             : 
     382             :     // The ordering of the bytecode and compiled file is significant and must
     383             :     // never be changed. These two files must always form a pair
     384             :     // [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
     385           0 :     if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
     386           0 :         !JS_WriteUint32Pair(aWriter, index, index + 1)) {
     387           0 :       return false;
     388             :     }
     389             : 
     390           0 :     StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
     391           0 :     newFile->mBlob = bytecodeBlob;
     392           0 :     newFile->mType = StructuredCloneFile::eWasmBytecode;
     393             : 
     394           0 :     newFile = cloneWriteInfo->mFiles.AppendElement();
     395           0 :     newFile->mBlob = compiledBlob;
     396           0 :     newFile->mType = StructuredCloneFile::eWasmCompiled;
     397             : 
     398           0 :     return true;
     399             :   }
     400             : 
     401           0 :   return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
     402             : }
     403             : 
     404             : nsresult
     405           0 : GetAddInfoCallback(JSContext* aCx, void* aClosure)
     406             : {
     407             :   static const JSStructuredCloneCallbacks kStructuredCloneCallbacks = {
     408             :     nullptr /* read */,
     409             :     StructuredCloneWriteCallback /* write */,
     410             :     nullptr /* reportError */,
     411             :     nullptr /* readTransfer */,
     412             :     nullptr /* writeTransfer */,
     413             :     nullptr /* freeTransfer */
     414             :   };
     415             : 
     416           0 :   MOZ_ASSERT(aCx);
     417             : 
     418           0 :   auto* data = static_cast<GetAddInfoClosure*>(aClosure);
     419           0 :   MOZ_ASSERT(data);
     420             : 
     421           0 :   data->mCloneWriteInfo.mOffsetToKeyProp = 0;
     422             : 
     423           0 :   if (!data->mCloneWriteInfo.mCloneBuffer.write(aCx,
     424             :                                                 data->mValue,
     425             :                                                 &kStructuredCloneCallbacks,
     426           0 :                                                 &data->mCloneWriteInfo)) {
     427           0 :     return NS_ERROR_DOM_DATA_CLONE_ERR;
     428             :   }
     429             : 
     430           0 :   return NS_OK;
     431             : }
     432             : 
     433             : bool
     434           0 : ResolveMysteryMutableFile(IDBMutableFile* aMutableFile,
     435             :                           const nsString& aName,
     436             :                           const nsString& aType)
     437             : {
     438           0 :   MOZ_ASSERT(aMutableFile);
     439           0 :   aMutableFile->SetLazyData(aName, aType);
     440           0 :   return true;
     441             : }
     442             : 
     443             : bool
     444           0 : StructuredCloneReadString(JSStructuredCloneReader* aReader,
     445             :                           nsCString& aString)
     446             : {
     447             :   uint32_t length;
     448           0 :   if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
     449           0 :     NS_WARNING("Failed to read length!");
     450           0 :     return false;
     451             :   }
     452           0 :   length = NativeEndian::swapFromLittleEndian(length);
     453             : 
     454           0 :   if (!aString.SetLength(length, fallible)) {
     455           0 :     NS_WARNING("Out of memory?");
     456           0 :     return false;
     457             :   }
     458           0 :   char* buffer = aString.BeginWriting();
     459             : 
     460           0 :   if (!JS_ReadBytes(aReader, buffer, length)) {
     461           0 :     NS_WARNING("Failed to read type!");
     462           0 :     return false;
     463             :   }
     464             : 
     465           0 :   return true;
     466             : }
     467             : 
     468             : bool
     469           0 : ReadFileHandle(JSStructuredCloneReader* aReader,
     470             :                MutableFileData* aRetval)
     471             : {
     472             :   static_assert(SCTAG_DOM_MUTABLEFILE == 0xFFFF8004, "Update me!");
     473           0 :   MOZ_ASSERT(aReader && aRetval);
     474             : 
     475           0 :   nsCString type;
     476           0 :   if (!StructuredCloneReadString(aReader, type)) {
     477           0 :     return false;
     478             :   }
     479           0 :   CopyUTF8toUTF16(type, aRetval->type);
     480             : 
     481           0 :   nsCString name;
     482           0 :   if (!StructuredCloneReadString(aReader, name)) {
     483           0 :     return false;
     484             :   }
     485           0 :   CopyUTF8toUTF16(name, aRetval->name);
     486             : 
     487           0 :   return true;
     488             : }
     489             : 
     490             : bool
     491           0 : ReadBlobOrFile(JSStructuredCloneReader* aReader,
     492             :                uint32_t aTag,
     493             :                BlobOrFileData* aRetval)
     494             : {
     495             :   static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
     496             :                 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
     497             :                 SCTAG_DOM_FILE == 0xffff8005,
     498             :                 "Update me!");
     499             : 
     500           0 :   MOZ_ASSERT(aReader);
     501           0 :   MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
     502             :              aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
     503             :              aTag == SCTAG_DOM_BLOB);
     504           0 :   MOZ_ASSERT(aRetval);
     505             : 
     506           0 :   aRetval->tag = aTag;
     507             : 
     508             :   uint64_t size;
     509           0 :   if (NS_WARN_IF(!JS_ReadBytes(aReader, &size, sizeof(uint64_t)))) {
     510           0 :     return false;
     511             :   }
     512             : 
     513           0 :   aRetval->size = NativeEndian::swapFromLittleEndian(size);
     514             : 
     515           0 :   nsCString type;
     516           0 :   if (NS_WARN_IF(!StructuredCloneReadString(aReader, type))) {
     517           0 :     return false;
     518             :   }
     519             : 
     520           0 :   CopyUTF8toUTF16(type, aRetval->type);
     521             : 
     522             :   // Blobs are done.
     523           0 :   if (aTag == SCTAG_DOM_BLOB) {
     524           0 :     return true;
     525             :   }
     526             : 
     527           0 :   MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
     528             :              aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);
     529             : 
     530             :   int64_t lastModifiedDate;
     531           0 :   if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
     532           0 :     lastModifiedDate = INT64_MAX;
     533             :   } else {
     534           0 :     if (NS_WARN_IF(!JS_ReadBytes(aReader, &lastModifiedDate,
     535             :                                 sizeof(lastModifiedDate)))) {
     536           0 :       return false;
     537             :     }
     538           0 :     lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
     539             :   }
     540             : 
     541           0 :   aRetval->lastModifiedDate = lastModifiedDate;
     542             : 
     543           0 :   nsCString name;
     544           0 :   if (NS_WARN_IF(!StructuredCloneReadString(aReader, name))) {
     545           0 :     return false;
     546             :   }
     547             : 
     548           0 :   CopyUTF8toUTF16(name, aRetval->name);
     549             : 
     550           0 :   return true;
     551             : }
     552             : 
     553             : bool
     554           0 : ReadWasmModule(JSStructuredCloneReader* aReader,
     555             :                WasmModuleData* aRetval)
     556             : {
     557             :   static_assert(SCTAG_DOM_WASM == 0xFFFF8006, "Update me!");
     558           0 :   MOZ_ASSERT(aReader && aRetval);
     559             : 
     560             :   uint32_t bytecodeIndex;
     561             :   uint32_t compiledIndex;
     562           0 :   if (NS_WARN_IF(!JS_ReadUint32Pair(aReader,
     563             :                                     &bytecodeIndex,
     564             :                                     &compiledIndex))) {
     565           0 :     return false;
     566             :   }
     567             : 
     568           0 :   aRetval->bytecodeIndex = bytecodeIndex;
     569           0 :   aRetval->compiledIndex = compiledIndex;
     570             : 
     571           0 :   return true;
     572             : }
     573             : 
     574             : class ValueDeserializationHelper
     575             : {
     576             : public:
     577             :   static bool
     578           0 :   CreateAndWrapMutableFile(JSContext* aCx,
     579             :                            StructuredCloneFile& aFile,
     580             :                            const MutableFileData& aData,
     581             :                            JS::MutableHandle<JSObject*> aResult)
     582             :   {
     583           0 :     MOZ_ASSERT(aCx);
     584           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eMutableFile);
     585             : 
     586           0 :     if (!aFile.mMutableFile || !NS_IsMainThread()) {
     587           0 :       return false;
     588             :     }
     589             : 
     590           0 :     if (NS_WARN_IF(!ResolveMysteryMutableFile(aFile.mMutableFile,
     591             :                                               aData.name,
     592             :                                               aData.type))) {
     593           0 :       return false;
     594             :     }
     595             : 
     596           0 :     JS::Rooted<JS::Value> wrappedMutableFile(aCx);
     597           0 :     if (!ToJSValue(aCx, aFile.mMutableFile, &wrappedMutableFile)) {
     598           0 :       return false;
     599             :     }
     600             : 
     601           0 :     aResult.set(&wrappedMutableFile.toObject());
     602           0 :     return true;
     603             :   }
     604             : 
     605             :   static bool
     606           0 :   CreateAndWrapBlobOrFile(JSContext* aCx,
     607             :                           IDBDatabase* aDatabase,
     608             :                           StructuredCloneFile& aFile,
     609             :                           const BlobOrFileData& aData,
     610             :                           JS::MutableHandle<JSObject*> aResult)
     611             :   {
     612           0 :     MOZ_ASSERT(aCx);
     613           0 :     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
     614             :                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
     615             :                aData.tag == SCTAG_DOM_BLOB);
     616           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
     617           0 :     MOZ_ASSERT(aFile.mBlob);
     618             : 
     619             :     // It can happen that this IDB is chrome code, so there is no parent, but
     620             :     // still we want to set a correct parent for the new File object.
     621           0 :     nsCOMPtr<nsISupports> parent;
     622           0 :     if (NS_IsMainThread()) {
     623           0 :       if (aDatabase && aDatabase->GetParentObject()) {
     624           0 :         parent = aDatabase->GetParentObject();
     625             :       } else {
     626           0 :         parent = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     627             :       }
     628             :     } else {
     629           0 :       WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
     630           0 :       MOZ_ASSERT(workerPrivate);
     631             : 
     632           0 :       WorkerGlobalScope* globalScope = workerPrivate->GlobalScope();
     633           0 :       MOZ_ASSERT(globalScope);
     634             : 
     635           0 :       parent = do_QueryObject(globalScope);
     636             :     }
     637             : 
     638           0 :     MOZ_ASSERT(parent);
     639             : 
     640           0 :     if (aData.tag == SCTAG_DOM_BLOB) {
     641           0 :       aFile.mBlob->Impl()->SetLazyData(
     642           0 :         NullString(), aData.type, aData.size, INT64_MAX);
     643           0 :       MOZ_ASSERT(!aFile.mBlob->IsFile());
     644             : 
     645             :       // ActorsParent sends here a kind of half blob and half file wrapped into
     646             :       // a DOM File object. DOM File and DOM Blob are a WebIDL wrapper around a
     647             :       // BlobImpl object. SetLazyData() has just changed the BlobImpl to be a
     648             :       // Blob (see the previous assert), but 'aFile.mBlob' still has the WebIDL
     649             :       // DOM File wrapping.
     650             :       // Before exposing it to content, we must recreate a DOM Blob object.
     651             : 
     652             :       RefPtr<Blob> blob =
     653           0 :         Blob::Create(aFile.mBlob->GetParentObject(), aFile.mBlob->Impl());
     654           0 :       MOZ_ASSERT(blob);
     655           0 :       JS::Rooted<JS::Value> wrappedBlob(aCx);
     656           0 :       if (!ToJSValue(aCx, blob, &wrappedBlob)) {
     657           0 :         return false;
     658             :       }
     659             : 
     660           0 :       aResult.set(&wrappedBlob.toObject());
     661           0 :       return true;
     662             :     }
     663             : 
     664           0 :     aFile.mBlob->Impl()->SetLazyData(
     665           0 :       aData.name, aData.type, aData.size,
     666           0 :       aData.lastModifiedDate * PR_USEC_PER_MSEC);
     667             : 
     668           0 :     MOZ_ASSERT(aFile.mBlob->IsFile());
     669           0 :     RefPtr<File> file = aFile.mBlob->ToFile();
     670           0 :     MOZ_ASSERT(file);
     671             : 
     672           0 :     JS::Rooted<JS::Value> wrappedFile(aCx);
     673           0 :     if (!ToJSValue(aCx, file, &wrappedFile)) {
     674           0 :       return false;
     675             :     }
     676             : 
     677           0 :     aResult.set(&wrappedFile.toObject());
     678           0 :     return true;
     679             :   }
     680             : 
     681             :   static bool
     682           0 :   CreateAndWrapWasmModule(JSContext* aCx,
     683             :                           StructuredCloneFile& aFile,
     684             :                           const WasmModuleData& aData,
     685             :                           JS::MutableHandle<JSObject*> aResult)
     686             :   {
     687           0 :     MOZ_ASSERT(aCx);
     688           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
     689           0 :     MOZ_ASSERT(!aFile.mBlob);
     690           0 :     MOZ_ASSERT(aFile.mWasmModule);
     691             : 
     692           0 :     JS::Rooted<JSObject*> moduleObj(aCx, aFile.mWasmModule->createObject(aCx));
     693           0 :     if (NS_WARN_IF(!moduleObj)) {
     694           0 :       return false;
     695             :     }
     696             : 
     697           0 :     aResult.set(moduleObj);
     698           0 :     return true;
     699             :   }
     700             : };
     701             : 
     702             : class IndexDeserializationHelper
     703             : {
     704             : public:
     705             :   static bool
     706           0 :   CreateAndWrapMutableFile(JSContext* aCx,
     707             :                            StructuredCloneFile& aFile,
     708             :                            const MutableFileData& aData,
     709             :                            JS::MutableHandle<JSObject*> aResult)
     710             :   {
     711             :     // MutableFile can't be used in index creation, so just make a dummy object.
     712           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
     713           0 :     if (NS_WARN_IF(!obj)) {
     714           0 :       return false;
     715             :     }
     716             : 
     717           0 :     aResult.set(obj);
     718           0 :     return true;
     719             :   }
     720             : 
     721             :   static bool
     722           0 :   CreateAndWrapBlobOrFile(JSContext* aCx,
     723             :                           IDBDatabase* aDatabase,
     724             :                           StructuredCloneFile& aFile,
     725             :                           const BlobOrFileData& aData,
     726             :                           JS::MutableHandle<JSObject*> aResult)
     727             :   {
     728           0 :     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
     729             :                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
     730             :                aData.tag == SCTAG_DOM_BLOB);
     731             : 
     732             :     // The following properties are available for use in index creation
     733             :     //   Blob.size
     734             :     //   Blob.type
     735             :     //   File.name
     736             :     //   File.lastModifiedDate
     737             : 
     738           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
     739           0 :     if (NS_WARN_IF(!obj)) {
     740           0 :       return false;
     741             :     }
     742             : 
     743             :     // Technically these props go on the proto, but this detail won't change
     744             :     // the results of index creation.
     745             : 
     746             :     JS::Rooted<JSString*> type(aCx,
     747           0 :       JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
     748           0 :     if (NS_WARN_IF(!type)) {
     749           0 :       return false;
     750             :     }
     751             : 
     752           0 :     if (NS_WARN_IF(!JS_DefineProperty(aCx,
     753             :                                       obj,
     754             :                                       "size",
     755             :                                       double(aData.size),
     756             :                                       0))) {
     757           0 :       return false;
     758             :     }
     759             : 
     760           0 :     if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "type", type, 0))) {
     761           0 :       return false;
     762             :     }
     763             : 
     764           0 :     if (aData.tag == SCTAG_DOM_BLOB) {
     765           0 :       aResult.set(obj);
     766           0 :       return true;
     767             :     }
     768             : 
     769             :     JS::Rooted<JSString*> name(aCx,
     770           0 :       JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length()));
     771           0 :     if (NS_WARN_IF(!name)) {
     772           0 :       return false;
     773             :     }
     774             : 
     775           0 :     JS::ClippedTime time = JS::TimeClip(aData.lastModifiedDate);
     776           0 :     JS::Rooted<JSObject*> date(aCx, JS::NewDateObject(aCx, time));
     777           0 :     if (NS_WARN_IF(!date)) {
     778           0 :       return false;
     779             :     }
     780             : 
     781           0 :     if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "name", name, 0))) {
     782           0 :       return false;
     783             :     }
     784             : 
     785           0 :     if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0))) {
     786           0 :       return false;
     787             :     }
     788             : 
     789           0 :     aResult.set(obj);
     790           0 :     return true;
     791             :   }
     792             : 
     793             :   static bool
     794           0 :   CreateAndWrapWasmModule(JSContext* aCx,
     795             :                           StructuredCloneFile& aFile,
     796             :                           const WasmModuleData& aData,
     797             :                           JS::MutableHandle<JSObject*> aResult)
     798             :   {
     799             :     // Wasm module can't be used in index creation, so just make a dummy object.
     800           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
     801           0 :     if (NS_WARN_IF(!obj)) {
     802           0 :       return false;
     803             :     }
     804             : 
     805           0 :     aResult.set(obj);
     806           0 :     return true;
     807             :   }
     808             : };
     809             : 
     810             : // We don't need to upgrade database on B2G. See the comment in ActorsParent.cpp,
     811             : // UpgradeSchemaFrom18_0To19_0()
     812             : #if !defined(MOZ_B2G)
     813             : 
     814             : class UpgradeDeserializationHelper
     815             : {
     816             : public:
     817             :   static bool
     818           0 :   CreateAndWrapMutableFile(JSContext* aCx,
     819             :                            StructuredCloneFile& aFile,
     820             :                            const MutableFileData& aData,
     821             :                            JS::MutableHandle<JSObject*> aResult)
     822             :   {
     823           0 :     MOZ_ASSERT(aCx);
     824           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
     825             : 
     826           0 :     aFile.mType = StructuredCloneFile::eMutableFile;
     827             : 
     828             :     // Just make a dummy object. The file_ids upgrade function is only
     829             :     // interested in the |mType| flag.
     830           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
     831             : 
     832           0 :     if (NS_WARN_IF(!obj)) {
     833           0 :       return false;
     834             :     }
     835             : 
     836           0 :     aResult.set(obj);
     837           0 :     return true;
     838             :   }
     839             : 
     840             :   static bool
     841           0 :   CreateAndWrapBlobOrFile(JSContext* aCx,
     842             :                           IDBDatabase* aDatabase,
     843             :                           StructuredCloneFile& aFile,
     844             :                           const BlobOrFileData& aData,
     845             :                           JS::MutableHandle<JSObject*> aResult)
     846             :   {
     847           0 :     MOZ_ASSERT(aCx);
     848           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
     849           0 :     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
     850             :                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
     851             :                aData.tag == SCTAG_DOM_BLOB);
     852             : 
     853             :     // Just make a dummy object. The file_ids upgrade function is only interested
     854             :     // in the |mType| flag.
     855           0 :     JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
     856             : 
     857           0 :     if (NS_WARN_IF(!obj)) {
     858           0 :       return false;
     859             :     }
     860             : 
     861           0 :     aResult.set(obj);
     862           0 :     return true;
     863             :   }
     864             : 
     865             :   static bool
     866           0 :   CreateAndWrapWasmModule(JSContext* aCx,
     867             :                           StructuredCloneFile& aFile,
     868             :                           const WasmModuleData& aData,
     869             :                           JS::MutableHandle<JSObject*> aResult)
     870             :   {
     871           0 :     MOZ_ASSERT(aCx);
     872           0 :     MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
     873             : 
     874           0 :     MOZ_ASSERT(false, "This should never be possible!");
     875             : 
     876             :     return false;
     877             :   }
     878             : };
     879             : 
     880             : #endif // MOZ_B2G
     881             : 
     882             : template <class Traits>
     883             : JSObject*
     884           0 : CommonStructuredCloneReadCallback(JSContext* aCx,
     885             :                                   JSStructuredCloneReader* aReader,
     886             :                                   uint32_t aTag,
     887             :                                   uint32_t aData,
     888             :                                   void* aClosure)
     889             : {
     890             :   // We need to statically assert that our tag values are what we expect
     891             :   // so that if people accidentally change them they notice.
     892             :   static_assert(SCTAG_DOM_BLOB == 0xffff8001 &&
     893             :                 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xffff8002 &&
     894             :                 SCTAG_DOM_MUTABLEFILE == 0xffff8004 &&
     895             :                 SCTAG_DOM_FILE == 0xffff8005 &&
     896             :                 SCTAG_DOM_WASM == 0xffff8006,
     897             :                 "You changed our structured clone tag values and just ate "
     898             :                 "everyone's IndexedDB data.  I hope you are happy.");
     899             : 
     900           0 :   if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
     901           0 :       aTag == SCTAG_DOM_BLOB ||
     902           0 :       aTag == SCTAG_DOM_FILE ||
     903           0 :       aTag == SCTAG_DOM_MUTABLEFILE ||
     904             :       aTag == SCTAG_DOM_WASM) {
     905           0 :     auto* cloneReadInfo = static_cast<StructuredCloneReadInfo*>(aClosure);
     906             : 
     907           0 :     JS::Rooted<JSObject*> result(aCx);
     908             : 
     909           0 :     if (aTag == SCTAG_DOM_WASM) {
     910           0 :       WasmModuleData data(aData);
     911           0 :       if (NS_WARN_IF(!ReadWasmModule(aReader, &data))) {
     912           0 :         return nullptr;
     913             :       }
     914             : 
     915           0 :       MOZ_ASSERT(data.compiledIndex == data.bytecodeIndex + 1);
     916           0 :       MOZ_ASSERT(!data.flags);
     917             : 
     918           0 :       if (data.bytecodeIndex >= cloneReadInfo->mFiles.Length() ||
     919           0 :           data.compiledIndex >= cloneReadInfo->mFiles.Length()) {
     920           0 :         MOZ_ASSERT(false, "Bad index value!");
     921             :         return nullptr;
     922             :       }
     923             : 
     924           0 :       StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
     925             : 
     926           0 :       if (NS_WARN_IF(!Traits::CreateAndWrapWasmModule(aCx,
     927             :                                                       file,
     928             :                                                       data,
     929             :                                                       &result))) {
     930           0 :         return nullptr;
     931             :       }
     932             : 
     933           0 :       return result;
     934             :     }
     935             : 
     936           0 :     if (aData >= cloneReadInfo->mFiles.Length()) {
     937           0 :       MOZ_ASSERT(false, "Bad index value!");
     938             :       return nullptr;
     939             :     }
     940             : 
     941           0 :     StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
     942             : 
     943           0 :     if (aTag == SCTAG_DOM_MUTABLEFILE) {
     944           0 :       MutableFileData data;
     945           0 :       if (NS_WARN_IF(!ReadFileHandle(aReader, &data))) {
     946           0 :         return nullptr;
     947             :       }
     948             : 
     949           0 :       if (NS_WARN_IF(!Traits::CreateAndWrapMutableFile(aCx,
     950             :                                                        file,
     951             :                                                        data,
     952             :                                                        &result))) {
     953           0 :         return nullptr;
     954             :       }
     955             : 
     956           0 :       return result;
     957             :     }
     958             : 
     959           0 :     BlobOrFileData data;
     960           0 :     if (NS_WARN_IF(!ReadBlobOrFile(aReader, aTag, &data))) {
     961           0 :       return nullptr;
     962             :     }
     963             : 
     964           0 :     if (NS_WARN_IF(!Traits::CreateAndWrapBlobOrFile(aCx,
     965             :                                                     cloneReadInfo->mDatabase,
     966             :                                                     file,
     967             :                                                     data,
     968             :                                                     &result))) {
     969           0 :       return nullptr;
     970             :     }
     971             : 
     972           0 :     return result;
     973             :   }
     974             : 
     975           0 :   return StructuredCloneHolder::ReadFullySerializableObjects(aCx, aReader,
     976           0 :                                                              aTag);
     977             : }
     978             : 
     979             : } // namespace
     980             : 
     981             : const JSClass IDBObjectStore::sDummyPropJSClass = {
     982             :   "IDBObjectStore Dummy",
     983             :   0 /* flags */
     984             : };
     985             : 
     986           0 : IDBObjectStore::IDBObjectStore(IDBTransaction* aTransaction,
     987           0 :                                const ObjectStoreSpec* aSpec)
     988             :   : mTransaction(aTransaction)
     989           0 :   , mCachedKeyPath(JS::UndefinedValue())
     990             :   , mSpec(aSpec)
     991           0 :   , mId(aSpec->metadata().id())
     992           0 :   , mRooted(false)
     993             : {
     994           0 :   MOZ_ASSERT(aTransaction);
     995           0 :   aTransaction->AssertIsOnOwningThread();
     996           0 :   MOZ_ASSERT(aSpec);
     997           0 : }
     998             : 
     999           0 : IDBObjectStore::~IDBObjectStore()
    1000             : {
    1001           0 :   AssertIsOnOwningThread();
    1002             : 
    1003           0 :   if (mRooted) {
    1004           0 :     mCachedKeyPath.setUndefined();
    1005           0 :     mozilla::DropJSObjects(this);
    1006             :   }
    1007           0 : }
    1008             : 
    1009             : // static
    1010             : already_AddRefed<IDBObjectStore>
    1011           0 : IDBObjectStore::Create(IDBTransaction* aTransaction,
    1012             :                        const ObjectStoreSpec& aSpec)
    1013             : {
    1014           0 :   MOZ_ASSERT(aTransaction);
    1015           0 :   aTransaction->AssertIsOnOwningThread();
    1016             : 
    1017             :   RefPtr<IDBObjectStore> objectStore =
    1018           0 :     new IDBObjectStore(aTransaction, &aSpec);
    1019             : 
    1020           0 :   return objectStore.forget();
    1021             : }
    1022             : 
    1023             : // static
    1024             : nsresult
    1025           0 : IDBObjectStore::AppendIndexUpdateInfo(
    1026             :                                     int64_t aIndexID,
    1027             :                                     const KeyPath& aKeyPath,
    1028             :                                     bool aUnique,
    1029             :                                     bool aMultiEntry,
    1030             :                                     const nsCString& aLocale,
    1031             :                                     JSContext* aCx,
    1032             :                                     JS::Handle<JS::Value> aVal,
    1033             :                                     nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
    1034             : {
    1035             :   nsresult rv;
    1036             : 
    1037             : #ifdef ENABLE_INTL_API
    1038           0 :   const bool localeAware = !aLocale.IsEmpty();
    1039             : #endif
    1040             : 
    1041           0 :   if (!aMultiEntry) {
    1042           0 :     Key key;
    1043           0 :     rv = aKeyPath.ExtractKey(aCx, aVal, key);
    1044             : 
    1045             :     // If an index's keyPath doesn't match an object, we ignore that object.
    1046           0 :     if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
    1047           0 :       return NS_OK;
    1048             :     }
    1049             : 
    1050           0 :     if (NS_FAILED(rv)) {
    1051           0 :       return rv;
    1052             :     }
    1053             : 
    1054           0 :     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
    1055           0 :     updateInfo->indexId() = aIndexID;
    1056           0 :     updateInfo->value() = key;
    1057             : #ifdef ENABLE_INTL_API
    1058           0 :     if (localeAware) {
    1059           0 :       rv = key.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
    1060           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1061           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1062             :       }
    1063             :     }
    1064             : #endif
    1065             : 
    1066           0 :     return NS_OK;
    1067             :   }
    1068             : 
    1069           0 :   JS::Rooted<JS::Value> val(aCx);
    1070           0 :   if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
    1071           0 :     return NS_OK;
    1072             :   }
    1073             : 
    1074             :   bool isArray;
    1075           0 :   if (!JS_IsArrayObject(aCx, val, &isArray)) {
    1076           0 :     IDB_REPORT_INTERNAL_ERR();
    1077           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1078             :   }
    1079           0 :   if (isArray) {
    1080           0 :     JS::Rooted<JSObject*> array(aCx, &val.toObject());
    1081             :     uint32_t arrayLength;
    1082           0 :     if (NS_WARN_IF(!JS_GetArrayLength(aCx, array, &arrayLength))) {
    1083           0 :       IDB_REPORT_INTERNAL_ERR();
    1084           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1085             :     }
    1086             : 
    1087           0 :     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
    1088           0 :       JS::Rooted<JS::Value> arrayItem(aCx);
    1089           0 :       if (NS_WARN_IF(!JS_GetElement(aCx, array, arrayIndex, &arrayItem))) {
    1090           0 :         IDB_REPORT_INTERNAL_ERR();
    1091           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1092             :       }
    1093             : 
    1094           0 :       Key value;
    1095           0 :       if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
    1096           0 :           value.IsUnset()) {
    1097             :         // Not a value we can do anything with, ignore it.
    1098           0 :         continue;
    1099             :       }
    1100             : 
    1101           0 :       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
    1102           0 :       updateInfo->indexId() = aIndexID;
    1103           0 :       updateInfo->value() = value;
    1104             : #ifdef ENABLE_INTL_API
    1105           0 :       if (localeAware) {
    1106           0 :         rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
    1107           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    1108           0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1109             :         }
    1110             :       }
    1111             : #endif
    1112             :     }
    1113             :   }
    1114             :   else {
    1115           0 :     Key value;
    1116           0 :     if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
    1117           0 :         value.IsUnset()) {
    1118             :       // Not a value we can do anything with, ignore it.
    1119           0 :       return NS_OK;
    1120             :     }
    1121             : 
    1122           0 :     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
    1123           0 :     updateInfo->indexId() = aIndexID;
    1124           0 :     updateInfo->value() = value;
    1125             : #ifdef ENABLE_INTL_API
    1126           0 :     if (localeAware) {
    1127           0 :       rv = value.ToLocaleBasedKey(updateInfo->localizedValue(), aLocale);
    1128           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    1129           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1130             :       }
    1131             :     }
    1132             : #endif
    1133             :   }
    1134             : 
    1135           0 :   return NS_OK;
    1136             : }
    1137             : 
    1138             : // static
    1139             : void
    1140           0 : IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
    1141             : {
    1142             :   // This is kind of tricky, we only want to release stuff on the main thread,
    1143             :   // but we can end up being called on other threads if we have already been
    1144             :   // cleared on the main thread.
    1145           0 :   if (!aReadInfo.mFiles.Length()) {
    1146           0 :     return;
    1147             :   }
    1148             : 
    1149           0 :   aReadInfo.mFiles.Clear();
    1150             : }
    1151             : 
    1152             : // static
    1153             : bool
    1154           0 : IDBObjectStore::DeserializeValue(JSContext* aCx,
    1155             :                                  StructuredCloneReadInfo& aCloneReadInfo,
    1156             :                                  JS::MutableHandle<JS::Value> aValue)
    1157             : {
    1158           0 :   MOZ_ASSERT(aCx);
    1159             : 
    1160           0 :   if (!aCloneReadInfo.mData.Size()) {
    1161           0 :     aValue.setUndefined();
    1162           0 :     return true;
    1163             :   }
    1164             : 
    1165           0 :   MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
    1166             : 
    1167           0 :   JSAutoRequest ar(aCx);
    1168             : 
    1169             :   static const JSStructuredCloneCallbacks callbacks = {
    1170             :     CommonStructuredCloneReadCallback<ValueDeserializationHelper>,
    1171             :     nullptr,
    1172             :     nullptr,
    1173             :     nullptr,
    1174             :     nullptr,
    1175             :     nullptr
    1176             :   };
    1177             : 
    1178             :   // FIXME: Consider to use StructuredCloneHolder here and in other
    1179             :   //        deserializing methods.
    1180           0 :   if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
    1181             :                               JS::StructuredCloneScope::SameProcessSameThread,
    1182             :                               aValue, &callbacks, &aCloneReadInfo)) {
    1183           0 :     return false;
    1184             :   }
    1185             : 
    1186           0 :   return true;
    1187             : }
    1188             : 
    1189             : // static
    1190             : bool
    1191           0 : IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
    1192             :                                       StructuredCloneReadInfo& aCloneReadInfo,
    1193             :                                       JS::MutableHandle<JS::Value> aValue)
    1194             : {
    1195           0 :   MOZ_ASSERT(!NS_IsMainThread());
    1196           0 :   MOZ_ASSERT(aCx);
    1197             : 
    1198           0 :   if (!aCloneReadInfo.mData.Size()) {
    1199           0 :     aValue.setUndefined();
    1200           0 :     return true;
    1201             :   }
    1202             : 
    1203           0 :   MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
    1204             : 
    1205           0 :   JSAutoRequest ar(aCx);
    1206             : 
    1207             :   static const JSStructuredCloneCallbacks callbacks = {
    1208             :     CommonStructuredCloneReadCallback<IndexDeserializationHelper>,
    1209             :     nullptr,
    1210             :     nullptr
    1211             :   };
    1212             : 
    1213           0 :   if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
    1214             :                               JS::StructuredCloneScope::SameProcessSameThread,
    1215             :                               aValue, &callbacks, &aCloneReadInfo)) {
    1216           0 :     return false;
    1217             :   }
    1218             : 
    1219           0 :   return true;
    1220             : }
    1221             : 
    1222             : #if !defined(MOZ_B2G)
    1223             : 
    1224             : // static
    1225             : bool
    1226           0 : IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
    1227             :                                         StructuredCloneReadInfo& aCloneReadInfo,
    1228             :                                         JS::MutableHandle<JS::Value> aValue)
    1229             : {
    1230           0 :   MOZ_ASSERT(!NS_IsMainThread());
    1231           0 :   MOZ_ASSERT(aCx);
    1232             : 
    1233           0 :   if (!aCloneReadInfo.mData.Size()) {
    1234           0 :     aValue.setUndefined();
    1235           0 :     return true;
    1236             :   }
    1237             : 
    1238           0 :   MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
    1239             : 
    1240           0 :   JSAutoRequest ar(aCx);
    1241             : 
    1242             :   static JSStructuredCloneCallbacks callbacks = {
    1243             :     CommonStructuredCloneReadCallback<UpgradeDeserializationHelper>,
    1244             :     nullptr,
    1245             :     nullptr,
    1246             :     nullptr,
    1247             :     nullptr,
    1248             :     nullptr
    1249             :   };
    1250             : 
    1251           0 :   if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
    1252             :                               JS::StructuredCloneScope::SameProcessSameThread,
    1253             :                               aValue, &callbacks, &aCloneReadInfo)) {
    1254           0 :     return false;
    1255             :   }
    1256             : 
    1257           0 :   return true;
    1258             : }
    1259             : 
    1260             : #endif // MOZ_B2G
    1261             : 
    1262             : #ifdef DEBUG
    1263             : 
    1264             : void
    1265           0 : IDBObjectStore::AssertIsOnOwningThread() const
    1266             : {
    1267           0 :   MOZ_ASSERT(mTransaction);
    1268           0 :   mTransaction->AssertIsOnOwningThread();
    1269           0 : }
    1270             : 
    1271             : #endif // DEBUG
    1272             : 
    1273             : nsresult
    1274           0 : IDBObjectStore::GetAddInfo(JSContext* aCx,
    1275             :                            JS::Handle<JS::Value> aValue,
    1276             :                            JS::Handle<JS::Value> aKeyVal,
    1277             :                            StructuredCloneWriteInfo& aCloneWriteInfo,
    1278             :                            Key& aKey,
    1279             :                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
    1280             : {
    1281             :   // Return DATA_ERR if a key was passed in and this objectStore uses inline
    1282             :   // keys.
    1283           0 :   if (!aKeyVal.isUndefined() && HasValidKeyPath()) {
    1284           0 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1285             :   }
    1286             : 
    1287           0 :   bool isAutoIncrement = AutoIncrement();
    1288             : 
    1289             :   nsresult rv;
    1290             : 
    1291           0 :   if (!HasValidKeyPath()) {
    1292             :     // Out-of-line keys must be passed in.
    1293           0 :     rv = aKey.SetFromJSVal(aCx, aKeyVal);
    1294           0 :     if (NS_FAILED(rv)) {
    1295           0 :       return rv;
    1296             :     }
    1297           0 :   } else if (!isAutoIncrement) {
    1298           0 :     rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
    1299           0 :     if (NS_FAILED(rv)) {
    1300           0 :       return rv;
    1301             :     }
    1302             :   }
    1303             : 
    1304             :   // Return DATA_ERR if no key was specified this isn't an autoIncrement
    1305             :   // objectStore.
    1306           0 :   if (aKey.IsUnset() && !isAutoIncrement) {
    1307           0 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    1308             :   }
    1309             : 
    1310             :   // Figure out indexes and the index values to update here.
    1311           0 :   const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
    1312             : 
    1313           0 :   const uint32_t idxCount = indexes.Length();
    1314           0 :   aUpdateInfoArray.SetCapacity(idxCount); // Pretty good estimate
    1315             : 
    1316           0 :   for (uint32_t idxIndex = 0; idxIndex < idxCount; idxIndex++) {
    1317           0 :     const IndexMetadata& metadata = indexes[idxIndex];
    1318             : 
    1319           0 :     rv = AppendIndexUpdateInfo(metadata.id(), metadata.keyPath(),
    1320           0 :                                metadata.unique(), metadata.multiEntry(),
    1321             :                                metadata.locale(), aCx, aValue,
    1322           0 :                                aUpdateInfoArray);
    1323           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1324           0 :       return rv;
    1325             :     }
    1326             :   }
    1327             : 
    1328           0 :   GetAddInfoClosure data(aCloneWriteInfo, aValue);
    1329             : 
    1330           0 :   if (isAutoIncrement && HasValidKeyPath()) {
    1331           0 :     MOZ_ASSERT(aKey.IsUnset());
    1332             : 
    1333           0 :     rv = GetKeyPath().ExtractOrCreateKey(aCx,
    1334             :                                          aValue,
    1335             :                                          aKey,
    1336             :                                          &GetAddInfoCallback,
    1337           0 :                                          &data);
    1338             :   } else {
    1339           0 :     rv = GetAddInfoCallback(aCx, &data);
    1340             :   }
    1341             : 
    1342           0 :   return rv;
    1343             : }
    1344             : 
    1345             : already_AddRefed<IDBRequest>
    1346           0 : IDBObjectStore::AddOrPut(JSContext* aCx,
    1347             :                          JS::Handle<JS::Value> aValue,
    1348             :                          JS::Handle<JS::Value> aKey,
    1349             :                          bool aOverwrite,
    1350             :                          bool aFromCursor,
    1351             :                          ErrorResult& aRv)
    1352             : {
    1353           0 :   AssertIsOnOwningThread();
    1354           0 :   MOZ_ASSERT(aCx);
    1355           0 :   MOZ_ASSERT_IF(aFromCursor, aOverwrite);
    1356             : 
    1357           0 :   if (mTransaction->GetMode() == IDBTransaction::CLEANUP ||
    1358           0 :       mDeletedSpec) {
    1359           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1360           0 :     return nullptr;
    1361             :   }
    1362             : 
    1363           0 :   if (!mTransaction->IsOpen()) {
    1364           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1365           0 :     return nullptr;
    1366             :   }
    1367             : 
    1368           0 :   if (!mTransaction->IsWriteAllowed()) {
    1369           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
    1370           0 :     return nullptr;
    1371             :   }
    1372             : 
    1373           0 :   JS::Rooted<JS::Value> value(aCx, aValue);
    1374           0 :   Key key;
    1375           0 :   StructuredCloneWriteInfo cloneWriteInfo(mTransaction->Database());
    1376           0 :   nsTArray<IndexUpdateInfo> updateInfo;
    1377             : 
    1378           0 :   aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
    1379           0 :   if (aRv.Failed()) {
    1380           0 :     return nullptr;
    1381             :   }
    1382             : 
    1383             :   // Check the size limit of the serialized message which mainly consists of
    1384             :   // a StructuredCloneBuffer, an encoded object key, and the encoded index keys.
    1385             :   // kMaxIDBMsgOverhead covers the minor stuff not included in this calculation
    1386             :   // because the precise calculation would slow down this AddOrPut operation.
    1387             :   static const size_t kMaxIDBMsgOverhead = 1024 * 1024; // 1MB
    1388             :   const uint32_t maximalSizeFromPref =
    1389           0 :     IndexedDatabaseManager::MaxSerializedMsgSize();
    1390           0 :   MOZ_ASSERT(maximalSizeFromPref > kMaxIDBMsgOverhead);
    1391           0 :   const size_t kMaxMessageSize = maximalSizeFromPref - kMaxIDBMsgOverhead;
    1392             : 
    1393           0 :   size_t indexUpdateInfoSize = 0;
    1394           0 :   for (size_t i = 0; i < updateInfo.Length(); i++) {
    1395           0 :     indexUpdateInfoSize += updateInfo[i].value().GetBuffer().Length();
    1396           0 :     indexUpdateInfoSize += updateInfo[i].localizedValue().GetBuffer().Length();
    1397             :   }
    1398             : 
    1399           0 :   size_t messageSize = cloneWriteInfo.mCloneBuffer.data().Size() +
    1400           0 :     key.GetBuffer().Length() + indexUpdateInfoSize;
    1401             : 
    1402           0 :   if (messageSize > kMaxMessageSize) {
    1403           0 :     IDB_REPORT_INTERNAL_ERR();
    1404           0 :     aRv.ThrowDOMException(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR,
    1405           0 :       nsPrintfCString("The serialized value is too large"
    1406             :                       " (size=%zu bytes, max=%zu bytes).",
    1407           0 :                       messageSize, kMaxMessageSize));
    1408           0 :     return nullptr;
    1409             :   }
    1410             : 
    1411           0 :   ObjectStoreAddPutParams commonParams;
    1412           0 :   commonParams.objectStoreId() = Id();
    1413           0 :   commonParams.cloneInfo().data().data = Move(cloneWriteInfo.mCloneBuffer.data());
    1414           0 :   commonParams.cloneInfo().offsetToKeyProp() = cloneWriteInfo.mOffsetToKeyProp;
    1415           0 :   commonParams.key() = key;
    1416           0 :   commonParams.indexUpdateInfos().SwapElements(updateInfo);
    1417             : 
    1418             :   // Convert any blobs or mutable files into FileAddInfo.
    1419           0 :   nsTArray<StructuredCloneFile>& files = cloneWriteInfo.mFiles;
    1420             : 
    1421           0 :   if (!files.IsEmpty()) {
    1422           0 :     const uint32_t count = files.Length();
    1423             : 
    1424           0 :     FallibleTArray<FileAddInfo> fileAddInfos;
    1425           0 :     if (NS_WARN_IF(!fileAddInfos.SetCapacity(count, fallible))) {
    1426           0 :       aRv = NS_ERROR_OUT_OF_MEMORY;
    1427           0 :       return nullptr;
    1428             :     }
    1429             : 
    1430           0 :     IDBDatabase* database = mTransaction->Database();
    1431             : 
    1432           0 :     for (uint32_t index = 0; index < count; index++) {
    1433           0 :       StructuredCloneFile& file = files[index];
    1434             : 
    1435           0 :       FileAddInfo* fileAddInfo = fileAddInfos.AppendElement(fallible);
    1436           0 :       MOZ_ASSERT(fileAddInfo);
    1437             : 
    1438           0 :       switch (file.mType) {
    1439             :         case StructuredCloneFile::eBlob: {
    1440           0 :           MOZ_ASSERT(file.mBlob);
    1441           0 :           MOZ_ASSERT(!file.mMutableFile);
    1442             : 
    1443             :           PBackgroundIDBDatabaseFileChild* fileActor =
    1444           0 :             database->GetOrCreateFileActorForBlob(file.mBlob);
    1445           0 :           if (NS_WARN_IF(!fileActor)) {
    1446           0 :             IDB_REPORT_INTERNAL_ERR();
    1447           0 :             aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1448           0 :             return nullptr;
    1449             :           }
    1450             : 
    1451           0 :           fileAddInfo->file() = fileActor;
    1452           0 :           fileAddInfo->type() = StructuredCloneFile::eBlob;
    1453             : 
    1454           0 :           break;
    1455             :         }
    1456             : 
    1457             :         case StructuredCloneFile::eMutableFile: {
    1458           0 :           MOZ_ASSERT(file.mMutableFile);
    1459           0 :           MOZ_ASSERT(!file.mBlob);
    1460             : 
    1461             :           PBackgroundMutableFileChild* mutableFileActor =
    1462           0 :             file.mMutableFile->GetBackgroundActor();
    1463           0 :           if (NS_WARN_IF(!mutableFileActor)) {
    1464           0 :             IDB_REPORT_INTERNAL_ERR();
    1465           0 :             aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1466           0 :             return nullptr;
    1467             :           }
    1468             : 
    1469           0 :           fileAddInfo->file() = mutableFileActor;
    1470           0 :           fileAddInfo->type() = StructuredCloneFile::eMutableFile;
    1471             : 
    1472           0 :           break;
    1473             :         }
    1474             : 
    1475             :         case StructuredCloneFile::eWasmBytecode:
    1476             :         case StructuredCloneFile::eWasmCompiled: {
    1477           0 :           MOZ_ASSERT(file.mBlob);
    1478           0 :           MOZ_ASSERT(!file.mMutableFile);
    1479             : 
    1480             :           PBackgroundIDBDatabaseFileChild* fileActor =
    1481           0 :             database->GetOrCreateFileActorForBlob(file.mBlob);
    1482           0 :           if (NS_WARN_IF(!fileActor)) {
    1483           0 :             IDB_REPORT_INTERNAL_ERR();
    1484           0 :             aRv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    1485           0 :             return nullptr;
    1486             :           }
    1487             : 
    1488           0 :           fileAddInfo->file() = fileActor;
    1489           0 :           fileAddInfo->type() = file.mType;
    1490             : 
    1491           0 :           break;
    1492             :         }
    1493             : 
    1494             :         default:
    1495           0 :           MOZ_CRASH("Should never get here!");
    1496             :       }
    1497             :     }
    1498             : 
    1499           0 :     commonParams.fileAddInfos().SwapElements(fileAddInfos);
    1500             :   }
    1501             : 
    1502           0 :   RequestParams params;
    1503           0 :   if (aOverwrite) {
    1504           0 :     params = ObjectStorePutParams(commonParams);
    1505             :   } else {
    1506           0 :     params = ObjectStoreAddParams(commonParams);
    1507             :   }
    1508             : 
    1509           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    1510           0 :   MOZ_ASSERT(request);
    1511             : 
    1512           0 :   if (!aFromCursor) {
    1513           0 :     if (aOverwrite) {
    1514           0 :       IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1515             :                      "database(%s).transaction(%s).objectStore(%s).put(%s)",
    1516             :                    "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.put()",
    1517             :                    IDB_LOG_ID_STRING(),
    1518             :                    mTransaction->LoggingSerialNumber(),
    1519             :                    request->LoggingSerialNumber(),
    1520             :                    IDB_LOG_STRINGIFY(mTransaction->Database()),
    1521             :                    IDB_LOG_STRINGIFY(mTransaction),
    1522             :                    IDB_LOG_STRINGIFY(this),
    1523             :                    IDB_LOG_STRINGIFY(key));
    1524             :     } else {
    1525           0 :       IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1526             :                      "database(%s).transaction(%s).objectStore(%s).add(%s)",
    1527             :                    "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.add()",
    1528             :                    IDB_LOG_ID_STRING(),
    1529             :                    mTransaction->LoggingSerialNumber(),
    1530             :                    request->LoggingSerialNumber(),
    1531             :                    IDB_LOG_STRINGIFY(mTransaction->Database()),
    1532             :                    IDB_LOG_STRINGIFY(mTransaction),
    1533             :                    IDB_LOG_STRINGIFY(this),
    1534             :                    IDB_LOG_STRINGIFY(key));
    1535             :     }
    1536             :   }
    1537             : 
    1538           0 :   mTransaction->StartRequest(request, params);
    1539             : 
    1540           0 :   return request.forget();
    1541             : }
    1542             : 
    1543             : already_AddRefed<IDBRequest>
    1544           0 : IDBObjectStore::GetAllInternal(bool aKeysOnly,
    1545             :                                JSContext* aCx,
    1546             :                                JS::Handle<JS::Value> aKey,
    1547             :                                const Optional<uint32_t>& aLimit,
    1548             :                                ErrorResult& aRv)
    1549             : {
    1550           0 :   AssertIsOnOwningThread();
    1551             : 
    1552           0 :   if (mDeletedSpec) {
    1553           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1554           0 :     return nullptr;
    1555             :   }
    1556             : 
    1557           0 :   if (!mTransaction->IsOpen()) {
    1558           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1559           0 :     return nullptr;
    1560             :   }
    1561             : 
    1562           0 :   RefPtr<IDBKeyRange> keyRange;
    1563           0 :   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1564           0 :   if (NS_WARN_IF(aRv.Failed())) {
    1565           0 :     return nullptr;
    1566             :   }
    1567             : 
    1568           0 :   const int64_t id = Id();
    1569             : 
    1570           0 :   OptionalKeyRange optionalKeyRange;
    1571           0 :   if (keyRange) {
    1572           0 :     SerializedKeyRange serializedKeyRange;
    1573           0 :     keyRange->ToSerialized(serializedKeyRange);
    1574           0 :     optionalKeyRange = serializedKeyRange;
    1575             :   } else {
    1576           0 :     optionalKeyRange = void_t();
    1577             :   }
    1578             : 
    1579           0 :   const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
    1580             : 
    1581           0 :   RequestParams params;
    1582           0 :   if (aKeysOnly) {
    1583           0 :     params = ObjectStoreGetAllKeysParams(id, optionalKeyRange, limit);
    1584             :   } else {
    1585           0 :     params = ObjectStoreGetAllParams(id, optionalKeyRange, limit);
    1586             :   }
    1587             : 
    1588           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    1589           0 :   MOZ_ASSERT(request);
    1590             : 
    1591           0 :   if (aKeysOnly) {
    1592           0 :     IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1593             :                    "database(%s).transaction(%s).objectStore(%s)."
    1594             :                    "getAllKeys(%s, %s)",
    1595             :                  "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAllKeys()",
    1596             :                  IDB_LOG_ID_STRING(),
    1597             :                  mTransaction->LoggingSerialNumber(),
    1598             :                  request->LoggingSerialNumber(),
    1599             :                  IDB_LOG_STRINGIFY(mTransaction->Database()),
    1600             :                  IDB_LOG_STRINGIFY(mTransaction),
    1601             :                  IDB_LOG_STRINGIFY(this),
    1602             :                  IDB_LOG_STRINGIFY(keyRange),
    1603             :                  IDB_LOG_STRINGIFY(aLimit));
    1604             :   } else {
    1605           0 :     IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1606             :                    "database(%s).transaction(%s).objectStore(%s)."
    1607             :                    "getAll(%s, %s)",
    1608             :                  "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.getAll()",
    1609             :                  IDB_LOG_ID_STRING(),
    1610             :                  mTransaction->LoggingSerialNumber(),
    1611             :                  request->LoggingSerialNumber(),
    1612             :                  IDB_LOG_STRINGIFY(mTransaction->Database()),
    1613             :                  IDB_LOG_STRINGIFY(mTransaction),
    1614             :                  IDB_LOG_STRINGIFY(this),
    1615             :                  IDB_LOG_STRINGIFY(keyRange),
    1616             :                  IDB_LOG_STRINGIFY(aLimit));
    1617             :   }
    1618             : 
    1619           0 :   mTransaction->StartRequest(request, params);
    1620             : 
    1621           0 :   return request.forget();
    1622             : }
    1623             : 
    1624             : already_AddRefed<IDBRequest>
    1625           0 : IDBObjectStore::Clear(JSContext* aCx, ErrorResult& aRv)
    1626             : {
    1627           0 :   AssertIsOnOwningThread();
    1628             : 
    1629           0 :   if (mDeletedSpec) {
    1630           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1631           0 :     return nullptr;
    1632             :   }
    1633             : 
    1634           0 :   if (!mTransaction->IsOpen()) {
    1635           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1636           0 :     return nullptr;
    1637             :   }
    1638             : 
    1639           0 :   if (!mTransaction->IsWriteAllowed()) {
    1640           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
    1641           0 :     return nullptr;
    1642             :   }
    1643             : 
    1644           0 :   ObjectStoreClearParams params;
    1645           0 :   params.objectStoreId() = Id();
    1646             : 
    1647           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    1648           0 :   MOZ_ASSERT(request);
    1649             : 
    1650           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1651             :                  "database(%s).transaction(%s).objectStore(%s).clear()",
    1652             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.clear()",
    1653             :                IDB_LOG_ID_STRING(),
    1654             :                mTransaction->LoggingSerialNumber(),
    1655             :                request->LoggingSerialNumber(),
    1656             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    1657             :                IDB_LOG_STRINGIFY(mTransaction),
    1658             :                IDB_LOG_STRINGIFY(this));
    1659             : 
    1660           0 :   mTransaction->StartRequest(request, params);
    1661             : 
    1662           0 :   return request.forget();
    1663             : }
    1664             : 
    1665             : already_AddRefed<IDBIndex>
    1666           0 : IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv)
    1667             : {
    1668           0 :   AssertIsOnOwningThread();
    1669             : 
    1670           0 :   if (mTransaction->IsCommittingOrDone() || mDeletedSpec) {
    1671           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    1672           0 :     return nullptr;
    1673             :   }
    1674             : 
    1675           0 :   const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
    1676             : 
    1677           0 :   const IndexMetadata* metadata = nullptr;
    1678             : 
    1679           0 :   for (uint32_t idxCount = indexes.Length(), idxIndex = 0;
    1680           0 :        idxIndex < idxCount;
    1681             :        idxIndex++) {
    1682           0 :     const IndexMetadata& index = indexes[idxIndex];
    1683           0 :     if (index.name() == aName) {
    1684           0 :       metadata = &index;
    1685           0 :       break;
    1686             :     }
    1687             :   }
    1688             : 
    1689           0 :   if (!metadata) {
    1690           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
    1691           0 :     return nullptr;
    1692             :   }
    1693             : 
    1694           0 :   const int64_t desiredId = metadata->id();
    1695             : 
    1696           0 :   RefPtr<IDBIndex> index;
    1697             : 
    1698           0 :   for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
    1699           0 :        idxIndex < idxCount;
    1700             :        idxIndex++) {
    1701           0 :     RefPtr<IDBIndex>& existingIndex = mIndexes[idxIndex];
    1702             : 
    1703           0 :     if (existingIndex->Id() == desiredId) {
    1704           0 :       index = existingIndex;
    1705           0 :       break;
    1706             :     }
    1707             :   }
    1708             : 
    1709           0 :   if (!index) {
    1710           0 :     index = IDBIndex::Create(this, *metadata);
    1711           0 :     MOZ_ASSERT(index);
    1712             : 
    1713           0 :     mIndexes.AppendElement(index);
    1714             :   }
    1715             : 
    1716           0 :   return index.forget();
    1717             : }
    1718             : 
    1719             : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
    1720             : 
    1721           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore)
    1722           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
    1723           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
    1724           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1725             : 
    1726           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
    1727           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
    1728           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexes)
    1729           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDeletedIndexes)
    1730           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1731             : 
    1732           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
    1733           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
    1734             : 
    1735             :   // Don't unlink mTransaction!
    1736             : 
    1737           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexes)
    1738           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mDeletedIndexes)
    1739             : 
    1740           0 :   tmp->mCachedKeyPath.setUndefined();
    1741             : 
    1742           0 :   if (tmp->mRooted) {
    1743           0 :     mozilla::DropJSObjects(tmp);
    1744           0 :     tmp->mRooted = false;
    1745             :   }
    1746           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1747             : 
    1748           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
    1749           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    1750           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    1751           0 : NS_INTERFACE_MAP_END
    1752             : 
    1753           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore)
    1754           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore)
    1755             : 
    1756             : JSObject*
    1757           0 : IDBObjectStore::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    1758             : {
    1759           0 :   return IDBObjectStoreBinding::Wrap(aCx, this, aGivenProto);
    1760             : }
    1761             : 
    1762             : nsPIDOMWindowInner*
    1763           0 : IDBObjectStore::GetParentObject() const
    1764             : {
    1765           0 :   return mTransaction->GetParentObject();
    1766             : }
    1767             : 
    1768             : void
    1769           0 : IDBObjectStore::GetKeyPath(JSContext* aCx,
    1770             :                            JS::MutableHandle<JS::Value> aResult,
    1771             :                            ErrorResult& aRv)
    1772             : {
    1773           0 :   if (!mCachedKeyPath.isUndefined()) {
    1774           0 :     aResult.set(mCachedKeyPath);
    1775           0 :     return;
    1776             :   }
    1777             : 
    1778           0 :   aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
    1779           0 :   if (NS_WARN_IF(aRv.Failed())) {
    1780           0 :     return;
    1781             :   }
    1782             : 
    1783           0 :   if (mCachedKeyPath.isGCThing()) {
    1784           0 :     mozilla::HoldJSObjects(this);
    1785           0 :     mRooted = true;
    1786             :   }
    1787             : 
    1788           0 :   aResult.set(mCachedKeyPath);
    1789             : }
    1790             : 
    1791             : already_AddRefed<DOMStringList>
    1792           0 : IDBObjectStore::IndexNames()
    1793             : {
    1794           0 :   AssertIsOnOwningThread();
    1795             : 
    1796           0 :   const nsTArray<IndexMetadata>& indexes = mSpec->indexes();
    1797             : 
    1798           0 :   RefPtr<DOMStringList> list = new DOMStringList();
    1799             : 
    1800           0 :   if (!indexes.IsEmpty()) {
    1801           0 :     nsTArray<nsString>& listNames = list->StringArray();
    1802           0 :     listNames.SetCapacity(indexes.Length());
    1803             : 
    1804           0 :     for (uint32_t index = 0; index < indexes.Length(); index++) {
    1805           0 :       listNames.InsertElementSorted(indexes[index].name());
    1806             :     }
    1807             :   }
    1808             : 
    1809           0 :   return list.forget();
    1810             : }
    1811             : 
    1812             : already_AddRefed<IDBRequest>
    1813           0 : IDBObjectStore::GetInternal(bool aKeyOnly,
    1814             :                             JSContext* aCx,
    1815             :                             JS::Handle<JS::Value> aKey,
    1816             :                             ErrorResult& aRv)
    1817             : {
    1818           0 :   AssertIsOnOwningThread();
    1819             : 
    1820           0 :   if (mDeletedSpec) {
    1821           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1822           0 :     return nullptr;
    1823             :   }
    1824             : 
    1825           0 :   if (!mTransaction->IsOpen()) {
    1826           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1827           0 :     return nullptr;
    1828             :   }
    1829             : 
    1830           0 :   RefPtr<IDBKeyRange> keyRange;
    1831           0 :   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1832           0 :   if (aRv.Failed()) {
    1833           0 :     return nullptr;
    1834             :   }
    1835             : 
    1836           0 :   if (!keyRange) {
    1837             :     // Must specify a key or keyRange for get().
    1838           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
    1839           0 :     return nullptr;
    1840             :   }
    1841             : 
    1842           0 :   const int64_t id = Id();
    1843             : 
    1844           0 :   SerializedKeyRange serializedKeyRange;
    1845           0 :   keyRange->ToSerialized(serializedKeyRange);
    1846             : 
    1847           0 :   RequestParams params;
    1848           0 :   if (aKeyOnly) {
    1849           0 :     params = ObjectStoreGetKeyParams(id, serializedKeyRange);
    1850             :   } else {
    1851           0 :     params = ObjectStoreGetParams(id, serializedKeyRange);
    1852             :   }
    1853             : 
    1854           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    1855           0 :   MOZ_ASSERT(request);
    1856             : 
    1857           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1858             :                  "database(%s).transaction(%s).objectStore(%s).get(%s)",
    1859             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.get()",
    1860             :                IDB_LOG_ID_STRING(),
    1861             :                mTransaction->LoggingSerialNumber(),
    1862             :                request->LoggingSerialNumber(),
    1863             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    1864             :                IDB_LOG_STRINGIFY(mTransaction),
    1865             :                IDB_LOG_STRINGIFY(this),
    1866             :                IDB_LOG_STRINGIFY(keyRange));
    1867             : 
    1868           0 :   mTransaction->StartRequest(request, params);
    1869             : 
    1870           0 :   return request.forget();
    1871             : }
    1872             : 
    1873             : already_AddRefed<IDBRequest>
    1874           0 : IDBObjectStore::DeleteInternal(JSContext* aCx,
    1875             :                                JS::Handle<JS::Value> aKey,
    1876             :                                bool aFromCursor,
    1877             :                                ErrorResult& aRv)
    1878             : {
    1879           0 :   AssertIsOnOwningThread();
    1880             : 
    1881           0 :   if (mDeletedSpec) {
    1882           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1883           0 :     return nullptr;
    1884             :   }
    1885             : 
    1886           0 :   if (!mTransaction->IsOpen()) {
    1887           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1888           0 :     return nullptr;
    1889             :   }
    1890             : 
    1891           0 :   if (!mTransaction->IsWriteAllowed()) {
    1892           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
    1893           0 :     return nullptr;
    1894             :   }
    1895             : 
    1896           0 :   RefPtr<IDBKeyRange> keyRange;
    1897           0 :   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    1898           0 :   if (NS_WARN_IF((aRv.Failed()))) {
    1899           0 :     return nullptr;
    1900             :   }
    1901             : 
    1902           0 :   if (!keyRange) {
    1903             :     // Must specify a key or keyRange for delete().
    1904           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
    1905           0 :     return nullptr;
    1906             :   }
    1907             : 
    1908           0 :   ObjectStoreDeleteParams params;
    1909           0 :   params.objectStoreId() = Id();
    1910           0 :   keyRange->ToSerialized(params.keyRange());
    1911             : 
    1912           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    1913           0 :   MOZ_ASSERT(request);
    1914             : 
    1915           0 :   if (!aFromCursor) {
    1916           0 :     IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    1917             :                    "database(%s).transaction(%s).objectStore(%s).delete(%s)",
    1918             :                  "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.delete()",
    1919             :                  IDB_LOG_ID_STRING(),
    1920             :                  mTransaction->LoggingSerialNumber(),
    1921             :                  request->LoggingSerialNumber(),
    1922             :                  IDB_LOG_STRINGIFY(mTransaction->Database()),
    1923             :                  IDB_LOG_STRINGIFY(mTransaction),
    1924             :                  IDB_LOG_STRINGIFY(this),
    1925             :                  IDB_LOG_STRINGIFY(keyRange));
    1926             :   }
    1927             : 
    1928           0 :   mTransaction->StartRequest(request, params);
    1929             : 
    1930           0 :   return request.forget();
    1931             : }
    1932             : 
    1933             : already_AddRefed<IDBIndex>
    1934           0 : IDBObjectStore::CreateIndex(const nsAString& aName,
    1935             :                             const StringOrStringSequence& aKeyPath,
    1936             :                             const IDBIndexParameters& aOptionalParameters,
    1937             :                             ErrorResult& aRv)
    1938             : {
    1939           0 :   AssertIsOnOwningThread();
    1940             : 
    1941           0 :   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
    1942           0 :       mDeletedSpec) {
    1943           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    1944           0 :     return nullptr;
    1945             :   }
    1946             : 
    1947           0 :   IDBTransaction* transaction = IDBTransaction::GetCurrent();
    1948           0 :   if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
    1949           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    1950           0 :     return nullptr;
    1951             :   }
    1952             : 
    1953           0 :   auto& indexes = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
    1954           0 :   for (uint32_t count = indexes.Length(), index = 0;
    1955           0 :        index < count;
    1956             :        index++) {
    1957           0 :     if (aName == indexes[index].name()) {
    1958           0 :       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
    1959           0 :       return nullptr;
    1960             :     }
    1961             :   }
    1962             : 
    1963           0 :   KeyPath keyPath(0);
    1964           0 :   if (aKeyPath.IsString()) {
    1965           0 :     if (NS_FAILED(KeyPath::Parse(aKeyPath.GetAsString(), &keyPath)) ||
    1966           0 :         !keyPath.IsValid()) {
    1967           0 :       aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    1968           0 :       return nullptr;
    1969             :     }
    1970             :   } else {
    1971           0 :     MOZ_ASSERT(aKeyPath.IsStringSequence());
    1972           0 :     if (aKeyPath.GetAsStringSequence().IsEmpty() ||
    1973           0 :         NS_FAILED(KeyPath::Parse(aKeyPath.GetAsStringSequence(), &keyPath)) ||
    1974           0 :         !keyPath.IsValid()) {
    1975           0 :       aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
    1976           0 :       return nullptr;
    1977             :     }
    1978             :   }
    1979             : 
    1980           0 :   if (aOptionalParameters.mMultiEntry && keyPath.IsArray()) {
    1981           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
    1982           0 :     return nullptr;
    1983             :   }
    1984             : 
    1985             : #ifdef DEBUG
    1986           0 :   for (uint32_t count = mIndexes.Length(), index = 0;
    1987           0 :        index < count;
    1988             :        index++) {
    1989           0 :     MOZ_ASSERT(mIndexes[index]->Name() != aName);
    1990             :   }
    1991             : #endif
    1992             : 
    1993             :   const IndexMetadata* oldMetadataElements =
    1994           0 :     indexes.IsEmpty() ? nullptr : indexes.Elements();
    1995             : 
    1996             :   // With this setup we only validate the passed in locale name by the time we
    1997             :   // get to encoding Keys. Maybe we should do it here right away and error out.
    1998             : 
    1999             :   // Valid locale names are always ASCII as per BCP-47.
    2000           0 :   nsCString locale = NS_LossyConvertUTF16toASCII(aOptionalParameters.mLocale);
    2001           0 :   bool autoLocale = locale.EqualsASCII("auto");
    2002             : #ifdef ENABLE_INTL_API
    2003           0 :   if (autoLocale) {
    2004           0 :     locale = IndexedDatabaseManager::GetLocale();
    2005             :   }
    2006             : #endif
    2007             : 
    2008           0 :   IndexMetadata* metadata = indexes.AppendElement(
    2009           0 :     IndexMetadata(transaction->NextIndexId(), nsString(aName), keyPath,
    2010             :                   locale,
    2011             :                   aOptionalParameters.mUnique,
    2012             :                   aOptionalParameters.mMultiEntry,
    2013           0 :                   autoLocale));
    2014             : 
    2015           0 :   if (oldMetadataElements &&
    2016           0 :       oldMetadataElements != indexes.Elements()) {
    2017           0 :     MOZ_ASSERT(indexes.Length() > 1);
    2018             : 
    2019             :     // Array got moved, update the spec pointers for all live indexes.
    2020           0 :     RefreshSpec(/* aMayDelete */ false);
    2021             :   }
    2022             : 
    2023           0 :   transaction->CreateIndex(this, *metadata);
    2024             : 
    2025           0 :   RefPtr<IDBIndex> index = IDBIndex::Create(this, *metadata);
    2026           0 :   MOZ_ASSERT(index);
    2027             : 
    2028           0 :   mIndexes.AppendElement(index);
    2029             : 
    2030             :   // Don't do this in the macro because we always need to increment the serial
    2031             :   // number to keep in sync with the parent.
    2032           0 :   const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
    2033             : 
    2034           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2035             :                  "database(%s).transaction(%s).objectStore(%s).createIndex(%s)",
    2036             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.createIndex()",
    2037             :                IDB_LOG_ID_STRING(),
    2038             :                mTransaction->LoggingSerialNumber(),
    2039             :                requestSerialNumber,
    2040             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    2041             :                IDB_LOG_STRINGIFY(mTransaction),
    2042             :                IDB_LOG_STRINGIFY(this),
    2043             :                IDB_LOG_STRINGIFY(index));
    2044             : 
    2045           0 :   return index.forget();
    2046             : }
    2047             : 
    2048             : void
    2049           0 : IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
    2050             : {
    2051           0 :   AssertIsOnOwningThread();
    2052             : 
    2053           0 :   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
    2054           0 :       mDeletedSpec) {
    2055           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    2056           0 :     return;
    2057             :   }
    2058             : 
    2059           0 :   IDBTransaction* transaction = IDBTransaction::GetCurrent();
    2060           0 :   if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
    2061           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    2062           0 :     return;
    2063             :   }
    2064             : 
    2065           0 :   auto& metadataArray = const_cast<nsTArray<IndexMetadata>&>(mSpec->indexes());
    2066             : 
    2067           0 :   int64_t foundId = 0;
    2068             : 
    2069           0 :   for (uint32_t metadataCount = metadataArray.Length(), metadataIndex = 0;
    2070           0 :        metadataIndex < metadataCount;
    2071             :        metadataIndex++) {
    2072           0 :     const IndexMetadata& metadata = metadataArray[metadataIndex];
    2073           0 :     MOZ_ASSERT(metadata.id());
    2074             : 
    2075           0 :     if (aName == metadata.name()) {
    2076           0 :       foundId = metadata.id();
    2077             : 
    2078             :       // Must do this before altering the metadata array!
    2079           0 :       for (uint32_t indexCount = mIndexes.Length(), indexIndex = 0;
    2080           0 :            indexIndex < indexCount;
    2081             :            indexIndex++) {
    2082           0 :         RefPtr<IDBIndex>& index = mIndexes[indexIndex];
    2083             : 
    2084           0 :         if (index->Id() == foundId) {
    2085           0 :           index->NoteDeletion();
    2086             : 
    2087             :           RefPtr<IDBIndex>* deletedIndex =
    2088           0 :             mDeletedIndexes.AppendElement();
    2089           0 :           deletedIndex->swap(mIndexes[indexIndex]);
    2090             : 
    2091           0 :           mIndexes.RemoveElementAt(indexIndex);
    2092           0 :           break;
    2093             :         }
    2094             :       }
    2095             : 
    2096           0 :       metadataArray.RemoveElementAt(metadataIndex);
    2097             : 
    2098           0 :       RefreshSpec(/* aMayDelete */ false);
    2099           0 :       break;
    2100             :     }
    2101             :   }
    2102             : 
    2103           0 :   if (!foundId) {
    2104           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
    2105           0 :     return;
    2106             :   }
    2107             : 
    2108             :   // Don't do this in the macro because we always need to increment the serial
    2109             :   // number to keep in sync with the parent.
    2110           0 :   const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
    2111             : 
    2112           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2113             :                  "database(%s).transaction(%s).objectStore(%s)."
    2114             :                  "deleteIndex(\"%s\")",
    2115             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.deleteIndex()",
    2116             :                IDB_LOG_ID_STRING(),
    2117             :                mTransaction->LoggingSerialNumber(),
    2118             :                requestSerialNumber,
    2119             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    2120             :                IDB_LOG_STRINGIFY(mTransaction),
    2121             :                IDB_LOG_STRINGIFY(this),
    2122             :                NS_ConvertUTF16toUTF8(aName).get());
    2123             : 
    2124           0 :   transaction->DeleteIndex(this, foundId);
    2125             : }
    2126             : 
    2127             : already_AddRefed<IDBRequest>
    2128           0 : IDBObjectStore::Count(JSContext* aCx,
    2129             :                       JS::Handle<JS::Value> aKey,
    2130             :                       ErrorResult& aRv)
    2131             : {
    2132           0 :   AssertIsOnOwningThread();
    2133             : 
    2134           0 :   if (mDeletedSpec) {
    2135           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    2136           0 :     return nullptr;
    2137             :   }
    2138             : 
    2139           0 :   if (!mTransaction->IsOpen()) {
    2140           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    2141           0 :     return nullptr;
    2142             :   }
    2143             : 
    2144           0 :   RefPtr<IDBKeyRange> keyRange;
    2145           0 :   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
    2146           0 :   if (aRv.Failed()) {
    2147           0 :     return nullptr;
    2148             :   }
    2149             : 
    2150           0 :   ObjectStoreCountParams params;
    2151           0 :   params.objectStoreId() = Id();
    2152             : 
    2153           0 :   if (keyRange) {
    2154           0 :     SerializedKeyRange serializedKeyRange;
    2155           0 :     keyRange->ToSerialized(serializedKeyRange);
    2156           0 :     params.optionalKeyRange() = serializedKeyRange;
    2157             :   } else {
    2158           0 :     params.optionalKeyRange() = void_t();
    2159             :   }
    2160             : 
    2161           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    2162           0 :   MOZ_ASSERT(request);
    2163             : 
    2164           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2165             :                  "database(%s).transaction(%s).objectStore(%s).count(%s)",
    2166             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
    2167             :                IDB_LOG_ID_STRING(),
    2168             :                mTransaction->LoggingSerialNumber(),
    2169             :                request->LoggingSerialNumber(),
    2170             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    2171             :                IDB_LOG_STRINGIFY(mTransaction),
    2172             :                IDB_LOG_STRINGIFY(this),
    2173             :                IDB_LOG_STRINGIFY(keyRange));
    2174             : 
    2175           0 :   mTransaction->StartRequest(request, params);
    2176             : 
    2177           0 :   return request.forget();
    2178             : }
    2179             : 
    2180             : already_AddRefed<IDBRequest>
    2181           0 : IDBObjectStore::OpenCursorInternal(bool aKeysOnly,
    2182             :                                    JSContext* aCx,
    2183             :                                    JS::Handle<JS::Value> aRange,
    2184             :                                    IDBCursorDirection aDirection,
    2185             :                                    ErrorResult& aRv)
    2186             : {
    2187           0 :   AssertIsOnOwningThread();
    2188           0 :   MOZ_ASSERT(aCx);
    2189             : 
    2190           0 :   if (mDeletedSpec) {
    2191           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    2192           0 :     return nullptr;
    2193             :   }
    2194             : 
    2195           0 :   if (!mTransaction->IsOpen()) {
    2196           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    2197           0 :     return nullptr;
    2198             :   }
    2199             : 
    2200           0 :   RefPtr<IDBKeyRange> keyRange;
    2201           0 :   aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
    2202           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2203           0 :     return nullptr;
    2204             :   }
    2205             : 
    2206           0 :   int64_t objectStoreId = Id();
    2207             : 
    2208           0 :   OptionalKeyRange optionalKeyRange;
    2209             : 
    2210           0 :   if (keyRange) {
    2211           0 :     SerializedKeyRange serializedKeyRange;
    2212           0 :     keyRange->ToSerialized(serializedKeyRange);
    2213             : 
    2214           0 :     optionalKeyRange = Move(serializedKeyRange);
    2215             :   } else {
    2216           0 :     optionalKeyRange = void_t();
    2217             :   }
    2218             : 
    2219           0 :   IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
    2220             : 
    2221           0 :   OpenCursorParams params;
    2222           0 :   if (aKeysOnly) {
    2223           0 :     ObjectStoreOpenKeyCursorParams openParams;
    2224           0 :     openParams.objectStoreId() = objectStoreId;
    2225           0 :     openParams.optionalKeyRange() = Move(optionalKeyRange);
    2226           0 :     openParams.direction() = direction;
    2227             : 
    2228           0 :     params = Move(openParams);
    2229             :   } else {
    2230           0 :     ObjectStoreOpenCursorParams openParams;
    2231           0 :     openParams.objectStoreId() = objectStoreId;
    2232           0 :     openParams.optionalKeyRange() = Move(optionalKeyRange);
    2233           0 :     openParams.direction() = direction;
    2234             : 
    2235           0 :     params = Move(openParams);
    2236             :   }
    2237             : 
    2238           0 :   RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
    2239           0 :   MOZ_ASSERT(request);
    2240             : 
    2241           0 :   if (aKeysOnly) {
    2242           0 :     IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2243             :                    "database(%s).transaction(%s).objectStore(%s)."
    2244             :                    "openKeyCursor(%s, %s)",
    2245             :                  "IndexedDB %s: C T[%lld] R[%llu]: "
    2246             :                    "IDBObjectStore.openKeyCursor()",
    2247             :                  IDB_LOG_ID_STRING(),
    2248             :                  mTransaction->LoggingSerialNumber(),
    2249             :                  request->LoggingSerialNumber(),
    2250             :                  IDB_LOG_STRINGIFY(mTransaction->Database()),
    2251             :                  IDB_LOG_STRINGIFY(mTransaction),
    2252             :                  IDB_LOG_STRINGIFY(this),
    2253             :                  IDB_LOG_STRINGIFY(keyRange),
    2254             :                  IDB_LOG_STRINGIFY(direction));
    2255             :   } else {
    2256           0 :     IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2257             :                    "database(%s).transaction(%s).objectStore(%s)."
    2258             :                    "openCursor(%s, %s)",
    2259             :                  "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.openCursor()",
    2260             :                  IDB_LOG_ID_STRING(),
    2261             :                  mTransaction->LoggingSerialNumber(),
    2262             :                  request->LoggingSerialNumber(),
    2263             :                  IDB_LOG_STRINGIFY(mTransaction->Database()),
    2264             :                  IDB_LOG_STRINGIFY(mTransaction),
    2265             :                  IDB_LOG_STRINGIFY(this),
    2266             :                  IDB_LOG_STRINGIFY(keyRange),
    2267             :                  IDB_LOG_STRINGIFY(direction));
    2268             :   }
    2269             : 
    2270             :   BackgroundCursorChild* actor =
    2271           0 :     new BackgroundCursorChild(request, this, direction);
    2272             : 
    2273           0 :   mTransaction->OpenCursor(actor, params);
    2274             : 
    2275           0 :   return request.forget();
    2276             : }
    2277             : 
    2278             : void
    2279           0 : IDBObjectStore::RefreshSpec(bool aMayDelete)
    2280             : {
    2281           0 :   AssertIsOnOwningThread();
    2282           0 :   MOZ_ASSERT_IF(mDeletedSpec, mSpec == mDeletedSpec);
    2283             : 
    2284           0 :   const DatabaseSpec* dbSpec = mTransaction->Database()->Spec();
    2285           0 :   MOZ_ASSERT(dbSpec);
    2286             : 
    2287           0 :   const nsTArray<ObjectStoreSpec>& objectStores = dbSpec->objectStores();
    2288             : 
    2289           0 :   bool found = false;
    2290             : 
    2291           0 :   for (uint32_t objCount = objectStores.Length(), objIndex = 0;
    2292           0 :        objIndex < objCount;
    2293             :        objIndex++) {
    2294           0 :     const ObjectStoreSpec& objSpec = objectStores[objIndex];
    2295             : 
    2296           0 :     if (objSpec.metadata().id() == Id()) {
    2297           0 :       mSpec = &objSpec;
    2298             : 
    2299           0 :       for (uint32_t idxCount = mIndexes.Length(), idxIndex = 0;
    2300           0 :            idxIndex < idxCount;
    2301             :            idxIndex++) {
    2302           0 :         mIndexes[idxIndex]->RefreshMetadata(aMayDelete);
    2303             :       }
    2304             : 
    2305           0 :       for (uint32_t idxCount = mDeletedIndexes.Length(), idxIndex = 0;
    2306           0 :            idxIndex < idxCount;
    2307             :            idxIndex++) {
    2308           0 :         mDeletedIndexes[idxIndex]->RefreshMetadata(false);
    2309             :       }
    2310             : 
    2311           0 :       found = true;
    2312           0 :       break;
    2313             :     }
    2314             :   }
    2315             : 
    2316           0 :   MOZ_ASSERT_IF(!aMayDelete && !mDeletedSpec, found);
    2317             : 
    2318           0 :   if (found) {
    2319           0 :     MOZ_ASSERT(mSpec != mDeletedSpec);
    2320           0 :     mDeletedSpec = nullptr;
    2321             :   } else {
    2322           0 :     NoteDeletion();
    2323             :   }
    2324           0 : }
    2325             : 
    2326             : const ObjectStoreSpec&
    2327           0 : IDBObjectStore::Spec() const
    2328             : {
    2329           0 :   AssertIsOnOwningThread();
    2330           0 :   MOZ_ASSERT(mSpec);
    2331             : 
    2332           0 :   return *mSpec;
    2333             : }
    2334             : 
    2335             : void
    2336           0 : IDBObjectStore::NoteDeletion()
    2337             : {
    2338           0 :   AssertIsOnOwningThread();
    2339           0 :   MOZ_ASSERT(mSpec);
    2340           0 :   MOZ_ASSERT(Id() == mSpec->metadata().id());
    2341             : 
    2342           0 :   if (mDeletedSpec) {
    2343           0 :     MOZ_ASSERT(mDeletedSpec == mSpec);
    2344           0 :     return;
    2345             :   }
    2346             : 
    2347             :   // Copy the spec here.
    2348           0 :   mDeletedSpec = new ObjectStoreSpec(*mSpec);
    2349           0 :   mDeletedSpec->indexes().Clear();
    2350             : 
    2351           0 :   mSpec = mDeletedSpec;
    2352             : 
    2353           0 :   if (!mIndexes.IsEmpty()) {
    2354           0 :     for (uint32_t count = mIndexes.Length(), index = 0;
    2355           0 :          index < count;
    2356             :          index++) {
    2357           0 :       mIndexes[index]->NoteDeletion();
    2358             :     }
    2359             :   }
    2360             : }
    2361             : 
    2362             : const nsString&
    2363           0 : IDBObjectStore::Name() const
    2364             : {
    2365           0 :   AssertIsOnOwningThread();
    2366           0 :   MOZ_ASSERT(mSpec);
    2367             : 
    2368           0 :   return mSpec->metadata().name();
    2369             : }
    2370             : 
    2371             : void
    2372           0 : IDBObjectStore::SetName(const nsAString& aName, ErrorResult& aRv)
    2373             : {
    2374           0 :   AssertIsOnOwningThread();
    2375             : 
    2376           0 :   if (mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
    2377           0 :       mDeletedSpec) {
    2378           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2379           0 :     return;
    2380             :   }
    2381             : 
    2382           0 :   IDBTransaction* transaction = IDBTransaction::GetCurrent();
    2383           0 :   if (!transaction || transaction != mTransaction || !transaction->IsOpen()) {
    2384           0 :     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
    2385           0 :     return;
    2386             :   }
    2387             : 
    2388           0 :   if (aName == mSpec->metadata().name()) {
    2389           0 :     return;
    2390             :   }
    2391             : 
    2392             :   // Cache logging string of this object store before renaming.
    2393           0 :   const LoggingString loggingOldObjectStore(this);
    2394             : 
    2395             :   nsresult rv =
    2396           0 :     transaction->Database()->RenameObjectStore(mSpec->metadata().id(),
    2397           0 :                                                aName);
    2398             : 
    2399           0 :   if (NS_FAILED(rv)) {
    2400           0 :     aRv.Throw(rv);
    2401           0 :     return;
    2402             :   }
    2403             : 
    2404             :   // Don't do this in the macro because we always need to increment the serial
    2405             :   // number to keep in sync with the parent.
    2406           0 :   const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
    2407             : 
    2408           0 :   IDB_LOG_MARK("IndexedDB %s: Child  Transaction[%lld] Request[%llu]: "
    2409             :                  "database(%s).transaction(%s).objectStore(%s).rename(%s)",
    2410             :                "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.rename()",
    2411             :                IDB_LOG_ID_STRING(),
    2412             :                mTransaction->LoggingSerialNumber(),
    2413             :                requestSerialNumber,
    2414             :                IDB_LOG_STRINGIFY(mTransaction->Database()),
    2415             :                IDB_LOG_STRINGIFY(mTransaction),
    2416             :                loggingOldObjectStore.get(),
    2417             :                IDB_LOG_STRINGIFY(this));
    2418             : 
    2419           0 :   transaction->RenameObjectStore(mSpec->metadata().id(), aName);
    2420             : }
    2421             : 
    2422             : bool
    2423           0 : IDBObjectStore::AutoIncrement() const
    2424             : {
    2425           0 :   AssertIsOnOwningThread();
    2426           0 :   MOZ_ASSERT(mSpec);
    2427             : 
    2428           0 :   return mSpec->metadata().autoIncrement();
    2429             : }
    2430             : 
    2431             : const indexedDB::KeyPath&
    2432           0 : IDBObjectStore::GetKeyPath() const
    2433             : {
    2434           0 :   AssertIsOnOwningThread();
    2435           0 :   MOZ_ASSERT(mSpec);
    2436             : 
    2437           0 :   return mSpec->metadata().keyPath();
    2438             : }
    2439             : 
    2440             : bool
    2441           0 : IDBObjectStore::HasValidKeyPath() const
    2442             : {
    2443           0 :   AssertIsOnOwningThread();
    2444           0 :   MOZ_ASSERT(mSpec);
    2445             : 
    2446           0 :   return GetKeyPath().IsValid();
    2447             : }
    2448             : 
    2449             : } // namespace dom
    2450             : } // namespace mozilla

Generated by: LCOV version 1.13