tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ActorsChild.cpp (88803B)


      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 file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "ActorsChild.h"
      8 
      9 #include <mozIRemoteLazyInputStream.h>
     10 
     11 #include <type_traits>
     12 
     13 #include "BackgroundChildImpl.h"
     14 #include "IDBDatabase.h"
     15 #include "IDBEvents.h"
     16 #include "IDBFactory.h"
     17 #include "IDBIndex.h"
     18 #include "IDBObjectStore.h"
     19 #include "IDBRequest.h"
     20 #include "IDBTransaction.h"
     21 #include "IndexedDBCommon.h"
     22 #include "IndexedDatabase.h"
     23 #include "IndexedDatabaseInlines.h"
     24 #include "ProfilerHelpers.h"
     25 #include "ReportInternalError.h"
     26 #include "ThreadLocal.h"
     27 #include "js/Array.h"               // JS::NewArrayObject, JS::SetArrayLength
     28 #include "js/Date.h"                // JS::NewDateObject, JS::TimeClip
     29 #include "js/PropertyAndElement.h"  // JS_DefineElement, JS_DefineProperty
     30 #include "mozilla/ArrayAlgorithm.h"
     31 #include "mozilla/BasicEvents.h"
     32 #include "mozilla/CycleCollectedJSRuntime.h"
     33 #include "mozilla/Encoding.h"
     34 #include "mozilla/Maybe.h"
     35 #include "mozilla/ProfilerLabels.h"
     36 #include "mozilla/TaskQueue.h"
     37 #include "mozilla/dom/BlobImpl.h"
     38 #include "mozilla/dom/BrowserChild.h"
     39 #include "mozilla/dom/Element.h"
     40 #include "mozilla/dom/Event.h"
     41 #include "mozilla/dom/IPCBlobUtils.h"
     42 #include "mozilla/dom/PermissionMessageUtils.h"
     43 #include "mozilla/dom/WorkerPrivate.h"
     44 #include "mozilla/dom/WorkerRunnable.h"
     45 #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileChild.h"
     46 #include "mozilla/dom/quota/ResultExtensions.h"
     47 #include "mozilla/ipc/BackgroundUtils.h"
     48 #include "nsCOMPtr.h"
     49 #include "nsContentUtils.h"
     50 #include "nsIAsyncInputStream.h"
     51 #include "nsIEventTarget.h"
     52 #include "nsIFileStreams.h"
     53 #include "nsNetCID.h"
     54 #include "nsPIDOMWindow.h"
     55 #include "nsThreadUtils.h"
     56 #include "nsTraceRefcnt.h"
     57 
     58 #ifdef DEBUG
     59 #  include "IndexedDatabaseManager.h"
     60 #endif
     61 
     62 #define GC_ON_IPC_MESSAGES 0
     63 
     64 #if defined(DEBUG) || GC_ON_IPC_MESSAGES
     65 
     66 #  include "js/GCAPI.h"
     67 #  include "nsJSEnvironment.h"
     68 
     69 #  define BUILD_GC_ON_IPC_MESSAGES
     70 
     71 #endif  // DEBUG || GC_ON_IPC_MESSAGES
     72 
     73 namespace mozilla {
     74 
     75 using ipc::PrincipalInfo;
     76 
     77 namespace dom::indexedDB {
     78 
     79 /*******************************************************************************
     80 * ThreadLocal
     81 ******************************************************************************/
     82 
     83 ThreadLocal::ThreadLocal(const nsID& aBackgroundChildLoggingId)
     84    : mLoggingInfo(aBackgroundChildLoggingId, 1, -1, 1),
     85      mLoggingIdString(aBackgroundChildLoggingId) {
     86  MOZ_COUNT_CTOR(mozilla::dom::indexedDB::ThreadLocal);
     87 }
     88 
     89 ThreadLocal::~ThreadLocal() {
     90  MOZ_COUNT_DTOR(mozilla::dom::indexedDB::ThreadLocal);
     91 }
     92 
     93 /*******************************************************************************
     94 * Helpers
     95 ******************************************************************************/
     96 
     97 namespace {
     98 
     99 void MaybeCollectGarbageOnIPCMessage() {
    100 #ifdef BUILD_GC_ON_IPC_MESSAGES
    101  static const bool kCollectGarbageOnIPCMessages =
    102 #  if GC_ON_IPC_MESSAGES
    103      true;
    104 #  else
    105      false;
    106 #  endif  // GC_ON_IPC_MESSAGES
    107 
    108  if (!kCollectGarbageOnIPCMessages) {
    109    return;
    110  }
    111 
    112  static bool haveWarnedAboutGC = false;
    113  static bool haveWarnedAboutNonMainThread = false;
    114 
    115  if (!haveWarnedAboutGC) {
    116    haveWarnedAboutGC = true;
    117    NS_WARNING("IndexedDB child actor GC debugging enabled!");
    118  }
    119 
    120  if (!NS_IsMainThread()) {
    121    if (!haveWarnedAboutNonMainThread) {
    122      haveWarnedAboutNonMainThread = true;
    123      NS_WARNING("Don't know how to GC on a non-main thread yet.");
    124    }
    125    return;
    126  }
    127 
    128  nsJSContext::GarbageCollectNow(JS::GCReason::DOM_IPC);
    129  nsJSContext::CycleCollectNow(CCReason::API);
    130 #endif  // BUILD_GC_ON_IPC_MESSAGES
    131 }
    132 
    133 class MOZ_STACK_CLASS AutoSetCurrentTransaction final {
    134  using BackgroundChildImpl = mozilla::ipc::BackgroundChildImpl;
    135 
    136  Maybe<IDBTransaction&> const mTransaction;
    137  Maybe<IDBTransaction&> mPreviousTransaction;
    138  ThreadLocal* mThreadLocal;
    139 
    140 public:
    141  AutoSetCurrentTransaction(const AutoSetCurrentTransaction&) = delete;
    142  AutoSetCurrentTransaction(AutoSetCurrentTransaction&&) = delete;
    143  AutoSetCurrentTransaction& operator=(const AutoSetCurrentTransaction&) =
    144      delete;
    145  AutoSetCurrentTransaction& operator=(AutoSetCurrentTransaction&&) = delete;
    146 
    147  explicit AutoSetCurrentTransaction(Maybe<IDBTransaction&> aTransaction)
    148      : mTransaction(aTransaction), mThreadLocal(nullptr) {
    149    if (aTransaction) {
    150      BackgroundChildImpl::ThreadLocal* threadLocal =
    151          BackgroundChildImpl::GetThreadLocalForCurrentThread();
    152      MOZ_ASSERT(threadLocal);
    153 
    154      // Hang onto this for resetting later.
    155      mThreadLocal = threadLocal->mIndexedDBThreadLocal.get();
    156      MOZ_ASSERT(mThreadLocal);
    157 
    158      // Save the current value.
    159      mPreviousTransaction = mThreadLocal->MaybeCurrentTransactionRef();
    160 
    161      // Set the new value.
    162      mThreadLocal->SetCurrentTransaction(aTransaction);
    163    }
    164  }
    165 
    166  ~AutoSetCurrentTransaction() {
    167    MOZ_ASSERT_IF(mThreadLocal, mTransaction);
    168    MOZ_ASSERT_IF(mThreadLocal,
    169                  ReferenceEquals(mThreadLocal->MaybeCurrentTransactionRef(),
    170                                  mTransaction));
    171 
    172    if (mThreadLocal) {
    173      // Reset old value.
    174      mThreadLocal->SetCurrentTransaction(mPreviousTransaction);
    175    }
    176  }
    177 };
    178 
    179 template <typename T>
    180 void SetResultAndDispatchSuccessEvent(
    181    const NotNull<RefPtr<IDBRequest>>& aRequest,
    182    const SafeRefPtr<IDBTransaction>& aTransaction, T& aPtr,
    183    RefPtr<Event> aEvent = nullptr);
    184 
    185 namespace detail {
    186 void DispatchSuccessEvent(const NotNull<RefPtr<IDBRequest>>& aRequest,
    187                          const SafeRefPtr<IDBTransaction>& aTransaction,
    188                          const RefPtr<Event>& aEvent);
    189 
    190 template <class T>
    191 std::enable_if_t<std::is_same_v<T, IDBDatabase> || std::is_same_v<T, IDBCursor>,
    192                 nsresult>
    193 GetResult(JSContext* aCx, T* aDOMObject, JS::MutableHandle<JS::Value> aResult) {
    194  if (!aDOMObject) {
    195    aResult.setNull();
    196    return NS_OK;
    197  }
    198 
    199  const bool ok = GetOrCreateDOMReflector(aCx, aDOMObject, aResult);
    200  if (NS_WARN_IF(!ok)) {
    201    IDB_REPORT_INTERNAL_ERR();
    202    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    203  }
    204 
    205  return NS_OK;
    206 }
    207 
    208 nsresult GetResult(JSContext* aCx, const JS::Handle<JS::Value>* aValue,
    209                   JS::MutableHandle<JS::Value> aResult) {
    210  aResult.set(*aValue);
    211  return NS_OK;
    212 }
    213 
    214 nsresult GetResult(JSContext* aCx, const uint64_t* aValue,
    215                   JS::MutableHandle<JS::Value> aResult) {
    216  aResult.set(JS::NumberValue(*aValue));
    217  return NS_OK;
    218 }
    219 
    220 nsresult GetResult(JSContext* aCx, StructuredCloneReadInfoChild&& aCloneInfo,
    221                   JS::MutableHandle<JS::Value> aResult) {
    222  const bool ok =
    223      IDBObjectStore::DeserializeValue(aCx, std::move(aCloneInfo), aResult);
    224 
    225  if (NS_WARN_IF(!ok)) {
    226    return NS_ERROR_DOM_DATA_CLONE_ERR;
    227  }
    228 
    229  return NS_OK;
    230 }
    231 
    232 nsresult GetResult(JSContext* aCx, StructuredCloneReadInfoChild* aCloneInfo,
    233                   JS::MutableHandle<JS::Value> aResult) {
    234  return GetResult(aCx, std::move(*aCloneInfo), aResult);
    235 }
    236 
    237 nsresult GetResult(JSContext* aCx,
    238                   nsTArray<StructuredCloneReadInfoChild>* aCloneInfos,
    239                   JS::MutableHandle<JS::Value> aResult) {
    240  JS::Rooted<JSObject*> array(aCx, JS::NewArrayObject(aCx, 0));
    241  if (NS_WARN_IF(!array)) {
    242    IDB_REPORT_INTERNAL_ERR();
    243    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    244  }
    245 
    246  if (!aCloneInfos->IsEmpty()) {
    247    const uint32_t count = aCloneInfos->Length();
    248 
    249    if (NS_WARN_IF(!JS::SetArrayLength(aCx, array, count))) {
    250      IDB_REPORT_INTERNAL_ERR();
    251      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    252    }
    253 
    254    for (uint32_t index = 0; index < count; index++) {
    255      auto& cloneInfo = aCloneInfos->ElementAt(index);
    256 
    257      JS::Rooted<JS::Value> value(aCx);
    258 
    259      const nsresult rv = GetResult(aCx, std::move(cloneInfo), &value);
    260      if (NS_WARN_IF(NS_FAILED(rv))) {
    261        return rv;
    262      }
    263 
    264      if (NS_WARN_IF(
    265              !JS_DefineElement(aCx, array, index, value, JSPROP_ENUMERATE))) {
    266        IDB_REPORT_INTERNAL_ERR();
    267        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    268      }
    269    }
    270  }
    271 
    272  aResult.setObject(*array);
    273  return NS_OK;
    274 }
    275 
    276 nsresult GetResult(JSContext* aCx, const Key* aKey,
    277                   JS::MutableHandle<JS::Value> aResult) {
    278  const nsresult rv = aKey->ToJSVal(aCx, aResult);
    279  if (NS_WARN_IF(NS_FAILED(rv))) {
    280    return rv;
    281  }
    282  return NS_OK;
    283 }
    284 
    285 nsresult GetResult(JSContext* aCx, const nsTArray<Key>* aKeys,
    286                   JS::MutableHandle<JS::Value> aResult) {
    287  JS::Rooted<JSObject*> array(aCx, JS::NewArrayObject(aCx, 0));
    288  if (NS_WARN_IF(!array)) {
    289    IDB_REPORT_INTERNAL_ERR();
    290    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    291  }
    292 
    293  if (!aKeys->IsEmpty()) {
    294    const uint32_t count = aKeys->Length();
    295 
    296    if (NS_WARN_IF(!JS::SetArrayLength(aCx, array, count))) {
    297      IDB_REPORT_INTERNAL_ERR();
    298      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    299    }
    300 
    301    for (uint32_t index = 0; index < count; index++) {
    302      const Key& key = aKeys->ElementAt(index);
    303      MOZ_ASSERT(!key.IsUnset());
    304 
    305      JS::Rooted<JS::Value> value(aCx);
    306 
    307      const nsresult rv = GetResult(aCx, &key, &value);
    308      if (NS_WARN_IF(NS_FAILED(rv))) {
    309        return rv;
    310      }
    311 
    312      if (NS_WARN_IF(
    313              !JS_DefineElement(aCx, array, index, value, JSPROP_ENUMERATE))) {
    314        IDB_REPORT_INTERNAL_ERR();
    315        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    316      }
    317    }
    318  }
    319 
    320  aResult.setObject(*array);
    321  return NS_OK;
    322 }
    323 }  // namespace detail
    324 
    325 auto DeserializeStructuredCloneFiles(
    326    IDBDatabase* aDatabase,
    327    const nsTArray<SerializedStructuredCloneFile>& aSerializedFiles,
    328    bool aForPreprocess) {
    329  MOZ_ASSERT_IF(aForPreprocess, aSerializedFiles.Length() == 1);
    330 
    331  return TransformIntoNewArray(
    332      aSerializedFiles,
    333      [aForPreprocess, &database = *aDatabase](
    334          const auto& serializedFile) -> StructuredCloneFileChild {
    335        MOZ_ASSERT_IF(
    336            aForPreprocess,
    337            serializedFile.type() == StructuredCloneFileBase::eStructuredClone);
    338 
    339        const NullableBlob& blob = serializedFile.file();
    340 
    341        switch (serializedFile.type()) {
    342          case StructuredCloneFileBase::eBlob: {
    343            MOZ_ASSERT(blob.type() == NullableBlob::TIPCBlob);
    344 
    345            const IPCBlob& ipcBlob = blob.get_IPCBlob();
    346 
    347            const RefPtr<BlobImpl> blobImpl =
    348                IPCBlobUtils::Deserialize(ipcBlob);
    349            MOZ_ASSERT(blobImpl);
    350 
    351            RefPtr<Blob> blob =
    352                Blob::Create(database.GetOwnerGlobal(), blobImpl);
    353            MOZ_ASSERT(blob);
    354 
    355            return {StructuredCloneFileBase::eBlob, std::move(blob)};
    356          }
    357 
    358          case StructuredCloneFileBase::eStructuredClone: {
    359            if (aForPreprocess) {
    360              MOZ_ASSERT(blob.type() == NullableBlob::TIPCBlob);
    361 
    362              const IPCBlob& ipcBlob = blob.get_IPCBlob();
    363 
    364              const RefPtr<BlobImpl> blobImpl =
    365                  IPCBlobUtils::Deserialize(ipcBlob);
    366              MOZ_ASSERT(blobImpl);
    367 
    368              RefPtr<Blob> blob =
    369                  Blob::Create(database.GetOwnerGlobal(), blobImpl);
    370              MOZ_ASSERT(blob);
    371 
    372              return {StructuredCloneFileBase::eStructuredClone,
    373                      std::move(blob)};
    374            }
    375            MOZ_ASSERT(blob.type() == NullableBlob::Tnull_t);
    376 
    377            return StructuredCloneFileChild{
    378                StructuredCloneFileBase::eStructuredClone};
    379          }
    380 
    381          case StructuredCloneFileBase::eMutableFile:
    382          case StructuredCloneFileBase::eWasmBytecode:
    383          case StructuredCloneFileBase::eWasmCompiled: {
    384            MOZ_ASSERT(blob.type() == NullableBlob::Tnull_t);
    385 
    386            return StructuredCloneFileChild{serializedFile.type()};
    387 
    388            // Don't set mBlob, support for storing WebAssembly.Modules has been
    389            // removed in bug 1469395. Support for de-serialization of
    390            // WebAssembly.Modules has been removed in bug 1561876. Support for
    391            // MutableFile has been removed in bug 1500343. Full removal is
    392            // tracked in bug 1487479.
    393          }
    394 
    395          default:
    396            MOZ_CRASH("Should never get here!");
    397        }
    398      });
    399 }
    400 
    401 JSStructuredCloneData PreprocessingNotSupported() {
    402  MOZ_CRASH("Preprocessing not (yet) supported!");
    403 }
    404 
    405 template <typename PreprocessInfoAccessor>
    406 StructuredCloneReadInfoChild DeserializeStructuredCloneReadInfo(
    407    SerializedStructuredCloneReadInfo&& aSerialized,
    408    IDBDatabase* const aDatabase,
    409    PreprocessInfoAccessor preprocessInfoAccessor) {
    410  // XXX Make this a class invariant of SerializedStructuredCloneReadInfo.
    411  MOZ_ASSERT_IF(aSerialized.hasPreprocessInfo(),
    412                0 == aSerialized.data().data.Size());
    413  return {aSerialized.hasPreprocessInfo() ? preprocessInfoAccessor()
    414                                          : std::move(aSerialized.data().data),
    415          DeserializeStructuredCloneFiles(aDatabase, aSerialized.files(),
    416                                          /* aForPreprocess */ false),
    417          aDatabase};
    418 }
    419 
    420 // TODO: Remove duplication between DispatchErrorEvent and DispatchSucessEvent.
    421 
    422 void DispatchErrorEvent(
    423    MovingNotNull<RefPtr<IDBRequest>> aRequest, nsresult aErrorCode,
    424    const SafeRefPtr<IDBTransaction>& aTransaction = nullptr,
    425    RefPtr<Event> aEvent = nullptr) {
    426  const RefPtr<IDBRequest> request = std::move(aRequest);
    427 
    428  request->AssertIsOnOwningThread();
    429  MOZ_ASSERT(NS_FAILED(aErrorCode));
    430  MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);
    431 
    432  AUTO_PROFILER_LABEL("IndexedDB:DispatchErrorEvent", DOM);
    433 
    434  request->SetError(aErrorCode);
    435 
    436  if (!aEvent) {
    437    // Make an error event and fire it at the target.
    438    aEvent = CreateGenericEvent(request, nsDependentString(kErrorEventType),
    439                                eDoesBubble, eCancelable);
    440  }
    441  MOZ_ASSERT(aEvent);
    442 
    443  // XXX This is redundant if we are called from
    444  // DispatchSuccessEvent.
    445  Maybe<AutoSetCurrentTransaction> asct;
    446  if (aTransaction) {
    447    asct.emplace(SomeRef(*aTransaction));
    448  }
    449 
    450  if (aTransaction && aTransaction->IsInactive()) {
    451    aTransaction->TransitionToActive();
    452  }
    453 
    454  if (aTransaction) {
    455    IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
    456        "Firing %s event with error 0x%x", "%s (0x%" PRIx32 ")",
    457        aTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(),
    458        IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
    459        static_cast<uint32_t>(aErrorCode));
    460  } else {
    461    IDB_LOG_MARK_CHILD_REQUEST("Firing %s event with error 0x%x",
    462                               "%s (0x%" PRIx32 ")",
    463                               request->LoggingSerialNumber(),
    464                               IDB_LOG_STRINGIFY(aEvent, kErrorEventType),
    465                               static_cast<uint32_t>(aErrorCode));
    466  }
    467 
    468  IgnoredErrorResult rv;
    469  const bool doDefault =
    470      request->DispatchEvent(*aEvent, CallerType::System, rv);
    471  if (NS_WARN_IF(rv.Failed())) {
    472    return;
    473  }
    474 
    475  MOZ_ASSERT(!aTransaction || aTransaction->IsActive() ||
    476             aTransaction->IsAborted() ||
    477             aTransaction->WasExplicitlyCommitted());
    478 
    479  if (aTransaction && aTransaction->IsActive()) {
    480    aTransaction->TransitionToInactive();
    481 
    482    // Do not abort the transaction here if this request is failed due to the
    483    // abortion of its transaction to ensure that the correct error cause of
    484    // the abort event be set in IDBTransaction::FireCompleteOrAbortEvents()
    485    // later.
    486    if (aErrorCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) {
    487      WidgetEvent* const internalEvent = aEvent->WidgetEventPtr();
    488      MOZ_ASSERT(internalEvent);
    489 
    490      if (internalEvent->mFlags.mExceptionWasRaised) {
    491        aTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
    492      } else if (doDefault) {
    493        aTransaction->Abort(request);
    494      }
    495    }
    496  }
    497 }
    498 
    499 template <typename T>
    500 void SetResultAndDispatchSuccessEvent(
    501    const NotNull<RefPtr<IDBRequest>>& aRequest,
    502    const SafeRefPtr<IDBTransaction>& aTransaction, T& aPtr,
    503    RefPtr<Event> aEvent) {
    504  const auto autoTransaction =
    505      AutoSetCurrentTransaction{aTransaction.maybeDeref()};
    506 
    507  AUTO_PROFILER_LABEL("IndexedDB:SetResultAndDispatchSuccessEvent", DOM);
    508 
    509  aRequest->AssertIsOnOwningThread();
    510 
    511  if (aTransaction && aTransaction->IsAborted()) {
    512    DispatchErrorEvent(aRequest, aTransaction->AbortCode(), aTransaction);
    513    return;
    514  }
    515 
    516  if (!aEvent) {
    517    aEvent =
    518        CreateGenericEvent(aRequest.get(), nsDependentString(kSuccessEventType),
    519                           eDoesNotBubble, eNotCancelable);
    520  }
    521  MOZ_ASSERT(aEvent);
    522 
    523  aRequest->SetResult(
    524      [&aPtr](JSContext* aCx, JS::MutableHandle<JS::Value> aResult) {
    525        MOZ_ASSERT(aCx);
    526        return detail::GetResult(aCx, &aPtr, aResult);
    527      });
    528 
    529  detail::DispatchSuccessEvent(aRequest, aTransaction, aEvent);
    530 }
    531 
    532 namespace detail {
    533 void DispatchSuccessEvent(const NotNull<RefPtr<IDBRequest>>& aRequest,
    534                          const SafeRefPtr<IDBTransaction>& aTransaction,
    535                          const RefPtr<Event>& aEvent) {
    536  if (aTransaction && aTransaction->IsInactive()) {
    537    aTransaction->TransitionToActive();
    538  }
    539 
    540  if (aTransaction) {
    541    IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
    542        "Firing %s event", "%s", aTransaction->LoggingSerialNumber(),
    543        aRequest->LoggingSerialNumber(),
    544        IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
    545  } else {
    546    IDB_LOG_MARK_CHILD_REQUEST("Firing %s event", "%s",
    547                               aRequest->LoggingSerialNumber(),
    548                               IDB_LOG_STRINGIFY(aEvent, kSuccessEventType));
    549  }
    550 
    551  MOZ_ASSERT_IF(aTransaction && !aTransaction->WasExplicitlyCommitted(),
    552                aTransaction->IsActive() && !aTransaction->IsAborted());
    553 
    554  IgnoredErrorResult rv;
    555  aRequest->DispatchEvent(*aEvent, rv);
    556  if (NS_WARN_IF(rv.Failed())) {
    557    return;
    558  }
    559 
    560  WidgetEvent* const internalEvent = aEvent->WidgetEventPtr();
    561  MOZ_ASSERT(internalEvent);
    562 
    563  if (aTransaction && aTransaction->IsActive()) {
    564    aTransaction->TransitionToInactive();
    565 
    566    if (internalEvent->mFlags.mExceptionWasRaised) {
    567      aTransaction->Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
    568    } else {
    569      // To handle upgrade transaction.
    570      aTransaction->CommitIfNotStarted();
    571    }
    572  }
    573 }
    574 }  // namespace detail
    575 
    576 PRFileDesc* GetFileDescriptorFromStream(nsIInputStream* aStream) {
    577  MOZ_ASSERT(aStream);
    578 
    579  const nsCOMPtr<nsIFileMetadata> fileMetadata = do_QueryInterface(aStream);
    580  if (NS_WARN_IF(!fileMetadata)) {
    581    return nullptr;
    582  }
    583 
    584  PRFileDesc* fileDesc;
    585  const nsresult rv = fileMetadata->GetFileDescriptor(&fileDesc);
    586  if (NS_WARN_IF(NS_FAILED(rv))) {
    587    return nullptr;
    588  }
    589 
    590  MOZ_ASSERT(fileDesc);
    591 
    592  return fileDesc;
    593 }
    594 
    595 auto GetKeyOperator(const IDBCursorDirection aDirection) {
    596  switch (aDirection) {
    597    case IDBCursorDirection::Next:
    598    case IDBCursorDirection::Nextunique:
    599      return &Key::operator>=;
    600    case IDBCursorDirection::Prev:
    601    case IDBCursorDirection::Prevunique:
    602      return &Key::operator<=;
    603    default:
    604      MOZ_CRASH("Should never get here.");
    605  }
    606 }
    607 
    608 // Does not need to be threadsafe since this only runs on one thread, but
    609 // inheriting from CancelableRunnable is easy.
    610 template <typename T>
    611 class DelayedActionRunnable final : public CancelableRunnable {
    612  using ActionFunc = void (T::*)();
    613 
    614  SafeRefPtr<T> mActor;
    615  RefPtr<IDBRequest> mRequest;
    616  ActionFunc mActionFunc;
    617 
    618 public:
    619  explicit DelayedActionRunnable(SafeRefPtr<T> aActor, ActionFunc aActionFunc)
    620      : CancelableRunnable("indexedDB::DelayedActionRunnable"),
    621        mActor(std::move(aActor)),
    622        mRequest(mActor->GetRequest()),
    623        mActionFunc(aActionFunc) {
    624    MOZ_ASSERT(mActor);
    625    mActor->AssertIsOnOwningThread();
    626    MOZ_ASSERT(mRequest);
    627    MOZ_ASSERT(mActionFunc);
    628  }
    629 
    630 private:
    631  ~DelayedActionRunnable() = default;
    632 
    633  NS_DECL_NSIRUNNABLE
    634  nsresult Cancel() override;
    635 };
    636 
    637 }  // namespace
    638 
    639 /*******************************************************************************
    640 * Actor class declarations
    641 ******************************************************************************/
    642 
    643 // DiscardableRunnable is used to make workers happy.
    644 class BackgroundRequestChild::PreprocessHelper final
    645    : public DiscardableRunnable,
    646      public nsIInputStreamCallback,
    647      public nsIFileMetadataCallback {
    648  enum class State {
    649    // Just created on the owning thread, dispatched to the thread pool. Next
    650    // step is either Finishing if stream was ready to be read or
    651    // WaitingForStreamReady if the stream is not ready.
    652    Initial,
    653 
    654    // Waiting for stream to be ready on a thread pool thread. Next state is
    655    // Finishing.
    656    WaitingForStreamReady,
    657 
    658    // Waiting to finish/finishing on the owning thread. Next step is Completed.
    659    Finishing,
    660 
    661    // All done.
    662    Completed
    663  };
    664 
    665  const nsCOMPtr<nsIEventTarget> mOwningEventTarget;
    666  RefPtr<TaskQueue> mTaskQueue;
    667  nsCOMPtr<nsIInputStream> mStream;
    668  UniquePtr<JSStructuredCloneData> mCloneData;
    669  BackgroundRequestChild* mActor;
    670  const uint32_t mCloneDataIndex;
    671  nsresult mResultCode;
    672  State mState;
    673 
    674 public:
    675  PreprocessHelper(uint32_t aCloneDataIndex, BackgroundRequestChild* aActor)
    676      : DiscardableRunnable(
    677            "indexedDB::BackgroundRequestChild::PreprocessHelper"),
    678        mOwningEventTarget(aActor->GetActorEventTarget()),
    679        mActor(aActor),
    680        mCloneDataIndex(aCloneDataIndex),
    681        mResultCode(NS_OK),
    682        mState(State::Initial) {
    683    AssertIsOnOwningThread();
    684    MOZ_ASSERT(aActor);
    685    aActor->AssertIsOnOwningThread();
    686  }
    687 
    688  bool IsOnOwningThread() const {
    689    MOZ_ASSERT(mOwningEventTarget);
    690 
    691    bool current;
    692    return NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)) &&
    693           current;
    694  }
    695 
    696  void AssertIsOnOwningThread() const { MOZ_ASSERT(IsOnOwningThread()); }
    697 
    698  void ClearActor() {
    699    AssertIsOnOwningThread();
    700 
    701    mActor = nullptr;
    702  }
    703 
    704  nsresult Init(const StructuredCloneFileChild& aFile);
    705 
    706  nsresult Dispatch();
    707 
    708 private:
    709  ~PreprocessHelper() {
    710    MOZ_ASSERT(mState == State::Initial || mState == State::Completed);
    711 
    712    if (mTaskQueue) {
    713      mTaskQueue->BeginShutdown();
    714    }
    715  }
    716 
    717  nsresult Start();
    718 
    719  nsresult ProcessStream();
    720 
    721  void Finish();
    722 
    723  NS_DECL_ISUPPORTS_INHERITED
    724  NS_DECL_NSIRUNNABLE
    725  NS_DECL_NSIINPUTSTREAMCALLBACK
    726  NS_DECL_NSIFILEMETADATACALLBACK
    727 };
    728 
    729 /*******************************************************************************
    730 * BackgroundRequestChildBase
    731 ******************************************************************************/
    732 
    733 BackgroundRequestChildBase::BackgroundRequestChildBase(
    734    MovingNotNull<RefPtr<IDBRequest>> aRequest)
    735    : mRequest(std::move(aRequest)) {
    736  mRequest->AssertIsOnOwningThread();
    737 
    738  MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChildBase);
    739 }
    740 
    741 BackgroundRequestChildBase::~BackgroundRequestChildBase() {
    742  AssertIsOnOwningThread();
    743 
    744  MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChildBase);
    745 }
    746 
    747 #ifdef DEBUG
    748 
    749 void BackgroundRequestChildBase::AssertIsOnOwningThread() const {
    750  mRequest->AssertIsOnOwningThread();
    751 }
    752 
    753 #endif  // DEBUG
    754 
    755 /*******************************************************************************
    756 * BackgroundFactoryChild
    757 ******************************************************************************/
    758 
    759 BackgroundFactoryChild::BackgroundFactoryChild(IDBFactory& aFactory)
    760    : mFactory(&aFactory) {
    761  AssertIsOnOwningThread();
    762  mFactory->AssertIsOnOwningThread();
    763 
    764  MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryChild);
    765 }
    766 
    767 BackgroundFactoryChild::~BackgroundFactoryChild() {
    768  MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryChild);
    769 }
    770 
    771 void BackgroundFactoryChild::SendDeleteMeInternal() {
    772  AssertIsOnOwningThread();
    773 
    774  if (mFactory) {
    775    mFactory->ClearBackgroundActor();
    776    mFactory = nullptr;
    777 
    778    MOZ_ALWAYS_TRUE(PBackgroundIDBFactoryChild::SendDeleteMe());
    779  }
    780 }
    781 
    782 void BackgroundFactoryChild::ActorDestroy(ActorDestroyReason aWhy) {
    783  AssertIsOnOwningThread();
    784 
    785  MaybeCollectGarbageOnIPCMessage();
    786 
    787  if (mFactory) {
    788    mFactory->ClearBackgroundActor();
    789 #ifdef DEBUG
    790    mFactory = nullptr;
    791 #endif
    792  }
    793 }
    794 
    795 PBackgroundIDBFactoryRequestChild*
    796 BackgroundFactoryChild::AllocPBackgroundIDBFactoryRequestChild(
    797    const FactoryRequestParams& aParams) {
    798  MOZ_CRASH(
    799      "PBackgroundIDBFactoryRequestChild actors should be manually "
    800      "constructed!");
    801 }
    802 
    803 bool BackgroundFactoryChild::DeallocPBackgroundIDBFactoryRequestChild(
    804    PBackgroundIDBFactoryRequestChild* aActor) {
    805  MOZ_ASSERT(aActor);
    806 
    807  delete static_cast<BackgroundFactoryRequestChild*>(aActor);
    808  return true;
    809 }
    810 
    811 already_AddRefed<PBackgroundIDBDatabaseChild>
    812 BackgroundFactoryChild::AllocPBackgroundIDBDatabaseChild(
    813    const DatabaseSpec& aSpec,
    814    PBackgroundIDBFactoryRequestChild* aRequest) const {
    815  AssertIsOnOwningThread();
    816 
    817  auto* const request = static_cast<BackgroundFactoryRequestChild*>(aRequest);
    818  MOZ_ASSERT(request);
    819 
    820  RefPtr<BackgroundDatabaseChild> actor =
    821      new BackgroundDatabaseChild(aSpec, request);
    822  return actor.forget();
    823 }
    824 
    825 mozilla::ipc::IPCResult
    826 BackgroundFactoryChild::RecvPBackgroundIDBDatabaseConstructor(
    827    PBackgroundIDBDatabaseChild* aActor, const DatabaseSpec& aSpec,
    828    NotNull<PBackgroundIDBFactoryRequestChild*> aRequest) {
    829  AssertIsOnOwningThread();
    830  MOZ_ASSERT(aActor);
    831 
    832  return IPC_OK();
    833 }
    834 
    835 /*******************************************************************************
    836 * BackgroundFactoryRequestChild
    837 ******************************************************************************/
    838 
    839 BackgroundFactoryRequestChild::BackgroundFactoryRequestChild(
    840    SafeRefPtr<IDBFactory> aFactory,
    841    MovingNotNull<RefPtr<IDBOpenDBRequest>> aOpenRequest, bool aIsDeleteOp,
    842    uint64_t aRequestedVersion)
    843    : BackgroundRequestChildBase(std::move(aOpenRequest)),
    844      mFactory(std::move(aFactory)),
    845      mDatabaseActor(nullptr),
    846      mRequestedVersion(aRequestedVersion),
    847      mIsDeleteOp(aIsDeleteOp) {
    848  // Can't assert owning thread here because IPDL has not yet set our manager!
    849  MOZ_ASSERT(mFactory);
    850  mFactory->AssertIsOnOwningThread();
    851 
    852  MOZ_COUNT_CTOR(indexedDB::BackgroundFactoryRequestChild);
    853 }
    854 
    855 BackgroundFactoryRequestChild::~BackgroundFactoryRequestChild() {
    856  MOZ_COUNT_DTOR(indexedDB::BackgroundFactoryRequestChild);
    857 }
    858 
    859 NotNull<IDBOpenDBRequest*> BackgroundFactoryRequestChild::GetOpenDBRequest()
    860    const {
    861  AssertIsOnOwningThread();
    862 
    863  // XXX NotNull might provide something to encapsulate this
    864  return WrapNotNullUnchecked(
    865      static_cast<IDBOpenDBRequest*>(mRequest.get().get()));
    866 }
    867 
    868 void BackgroundFactoryRequestChild::SetDatabaseActor(
    869    BackgroundDatabaseChild* aActor) {
    870  AssertIsOnOwningThread();
    871  MOZ_ASSERT(!aActor || !mDatabaseActor);
    872 
    873  mDatabaseActor = aActor;
    874 }
    875 
    876 void BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse) {
    877  AssertIsOnOwningThread();
    878  MOZ_ASSERT(NS_FAILED(aResponse));
    879  MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
    880 
    881  mRequest->Reset();
    882 
    883  DispatchErrorEvent(mRequest, aResponse);
    884 
    885  if (mDatabaseActor) {
    886    mDatabaseActor->ReleaseDOMObject();
    887    MOZ_ASSERT(!mDatabaseActor);
    888  }
    889 }
    890 
    891 void BackgroundFactoryRequestChild::HandleResponse(
    892    const OpenDatabaseRequestResponse& aResponse) {
    893  AssertIsOnOwningThread();
    894 
    895  mRequest->Reset();
    896 
    897  auto* databaseActor = static_cast<BackgroundDatabaseChild*>(
    898      aResponse.database().AsChild().get());
    899  MOZ_ASSERT(databaseActor);
    900 
    901  IDBDatabase* const database = [this, databaseActor]() -> IDBDatabase* {
    902    IDBDatabase* database = databaseActor->GetDOMObject();
    903    if (!database) {
    904      (void)this;
    905 
    906      if (NS_WARN_IF(!databaseActor->EnsureDOMObject())) {
    907        return nullptr;
    908      }
    909      MOZ_ASSERT(mDatabaseActor);
    910 
    911      database = databaseActor->GetDOMObject();
    912      MOZ_ASSERT(database);
    913    }
    914 
    915    return database;
    916  }();
    917 
    918  if (!database || database->IsClosed()) {
    919    // If the database was closed already, which is only possible if we fired an
    920    // "upgradeneeded" event, then we shouldn't fire a "success" event here.
    921    // Instead we fire an error event with AbortErr.
    922    DispatchErrorEvent(mRequest, NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
    923  } else {
    924    SetResultAndDispatchSuccessEvent(mRequest, nullptr, *database);
    925  }
    926 
    927  if (database) {
    928    MOZ_ASSERT(mDatabaseActor == databaseActor);
    929 
    930    databaseActor->ReleaseDOMObject();
    931  } else {
    932    databaseActor->SendDeleteMeInternal();
    933  }
    934  MOZ_ASSERT(!mDatabaseActor);
    935 }
    936 
    937 void BackgroundFactoryRequestChild::HandleResponse(
    938    const DeleteDatabaseRequestResponse& aResponse) {
    939  AssertIsOnOwningThread();
    940 
    941  RefPtr<Event> successEvent = IDBVersionChangeEvent::Create(
    942      mRequest.get(), nsDependentString(kSuccessEventType),
    943      aResponse.previousVersion());
    944  MOZ_ASSERT(successEvent);
    945 
    946  SetResultAndDispatchSuccessEvent(mRequest, nullptr, JS::UndefinedHandleValue,
    947                                   std::move(successEvent));
    948 
    949  MOZ_ASSERT(!mDatabaseActor);
    950 }
    951 
    952 void BackgroundFactoryRequestChild::ActorDestroy(ActorDestroyReason aWhy) {
    953  AssertIsOnOwningThread();
    954 
    955  MaybeCollectGarbageOnIPCMessage();
    956 
    957  if (aWhy != Deletion) {
    958    GetOpenDBRequest()->NoteComplete();
    959  }
    960 }
    961 
    962 mozilla::ipc::IPCResult BackgroundFactoryRequestChild::Recv__delete__(
    963    const FactoryRequestResponse& aResponse) {
    964  AssertIsOnOwningThread();
    965 
    966  MaybeCollectGarbageOnIPCMessage();
    967 
    968  switch (aResponse.type()) {
    969    case FactoryRequestResponse::Tnsresult:
    970      HandleResponse(aResponse.get_nsresult());
    971      break;
    972 
    973    case FactoryRequestResponse::TOpenDatabaseRequestResponse:
    974      HandleResponse(aResponse.get_OpenDatabaseRequestResponse());
    975      break;
    976 
    977    case FactoryRequestResponse::TDeleteDatabaseRequestResponse:
    978      HandleResponse(aResponse.get_DeleteDatabaseRequestResponse());
    979      break;
    980 
    981    default:
    982      return IPC_FAIL(this, "Unknown response type!");
    983  }
    984 
    985  auto request = GetOpenDBRequest();
    986  request->NoteComplete();
    987 
    988  return IPC_OK();
    989 }
    990 
    991 mozilla::ipc::IPCResult BackgroundFactoryRequestChild::RecvBlocked(
    992    const uint64_t aCurrentVersion) {
    993  AssertIsOnOwningThread();
    994 
    995  MaybeCollectGarbageOnIPCMessage();
    996 
    997  const nsDependentString type(kBlockedEventType);
    998 
    999  RefPtr<Event> blockedEvent;
   1000  if (mIsDeleteOp) {
   1001    blockedEvent =
   1002        IDBVersionChangeEvent::Create(mRequest.get(), type, aCurrentVersion);
   1003    MOZ_ASSERT(blockedEvent);
   1004  } else {
   1005    blockedEvent = IDBVersionChangeEvent::Create(
   1006        mRequest.get(), type, aCurrentVersion, mRequestedVersion);
   1007    MOZ_ASSERT(blockedEvent);
   1008  }
   1009 
   1010  RefPtr<IDBRequest> kungFuDeathGrip = mRequest;
   1011 
   1012  IDB_LOG_MARK_CHILD_REQUEST("Firing \"blocked\" event", "\"blocked\"",
   1013                             kungFuDeathGrip->LoggingSerialNumber());
   1014 
   1015  IgnoredErrorResult rv;
   1016  kungFuDeathGrip->DispatchEvent(*blockedEvent, rv);
   1017  if (rv.Failed()) {
   1018    NS_WARNING("Failed to dispatch event!");
   1019  }
   1020 
   1021  return IPC_OK();
   1022 }
   1023 
   1024 /*******************************************************************************
   1025 * BackgroundDatabaseChild
   1026 ******************************************************************************/
   1027 
   1028 BackgroundDatabaseChild::BackgroundDatabaseChild(
   1029    const DatabaseSpec& aSpec, BackgroundFactoryRequestChild* aOpenRequestActor)
   1030    : mSpec(MakeUnique<DatabaseSpec>(aSpec)),
   1031      mOpenRequestActor(aOpenRequestActor),
   1032      mDatabase(nullptr),
   1033      mPendingInvalidate(false) {
   1034  // Can't assert owning thread here because IPDL has not yet set our manager!
   1035  MOZ_ASSERT(aOpenRequestActor);
   1036 
   1037  MOZ_COUNT_CTOR(indexedDB::BackgroundDatabaseChild);
   1038 }
   1039 
   1040 BackgroundDatabaseChild::~BackgroundDatabaseChild() {
   1041  MOZ_COUNT_DTOR(indexedDB::BackgroundDatabaseChild);
   1042 }
   1043 
   1044 #ifdef DEBUG
   1045 
   1046 void BackgroundDatabaseChild::AssertIsOnOwningThread() const {
   1047  static_cast<BackgroundFactoryChild*>(Manager())->AssertIsOnOwningThread();
   1048 }
   1049 
   1050 #endif  // DEBUG
   1051 
   1052 void BackgroundDatabaseChild::SendDeleteMeInternal() {
   1053  AssertIsOnOwningThread();
   1054  MOZ_ASSERT(!mTemporaryStrongDatabase);
   1055  MOZ_ASSERT(!mOpenRequestActor);
   1056 
   1057  if (mDatabase) {
   1058    mDatabase->ClearBackgroundActor();
   1059    mDatabase = nullptr;
   1060 
   1061    MOZ_ALWAYS_TRUE(PBackgroundIDBDatabaseChild::SendDeleteMe());
   1062  }
   1063 }
   1064 
   1065 bool BackgroundDatabaseChild::EnsureDOMObject() {
   1066  AssertIsOnOwningThread();
   1067  MOZ_ASSERT(mOpenRequestActor);
   1068 
   1069  if (mTemporaryStrongDatabase) {
   1070    MOZ_ASSERT(!mSpec);
   1071    MOZ_ASSERT(mDatabase == mTemporaryStrongDatabase);
   1072    return true;
   1073  }
   1074 
   1075  MOZ_ASSERT(mSpec);
   1076 
   1077  const auto request = mOpenRequestActor->GetOpenDBRequest();
   1078 
   1079  auto& factory =
   1080      static_cast<BackgroundFactoryChild*>(Manager())->GetDOMObject();
   1081 
   1082  if (!factory.GetOwnerGlobal()) {
   1083    // Already disconnected from global.
   1084 
   1085    // We need to clear mOpenRequestActor here, since that would otherwise be
   1086    // done by ReleaseDOMObject, which cannot be called if EnsureDOMObject
   1087    // failed.
   1088    mOpenRequestActor = nullptr;
   1089 
   1090    return false;
   1091  }
   1092 
   1093  // TODO: This AcquireStrongRefFromRawPtr looks suspicious. This should be
   1094  // changed or at least well explained, see also comment on
   1095  // BackgroundFactoryChild.
   1096  mTemporaryStrongDatabase = IDBDatabase::Create(
   1097      request, SafeRefPtr{&factory, AcquireStrongRefFromRawPtr{}}, this,
   1098      std::move(mSpec));
   1099 
   1100  MOZ_ASSERT(mTemporaryStrongDatabase);
   1101  mTemporaryStrongDatabase->AssertIsOnOwningThread();
   1102 
   1103  mDatabase = mTemporaryStrongDatabase;
   1104 
   1105  if (mPendingInvalidate) {
   1106    mDatabase->Invalidate();
   1107    mPendingInvalidate = false;
   1108  }
   1109 
   1110  mOpenRequestActor->SetDatabaseActor(this);
   1111 
   1112  return true;
   1113 }
   1114 
   1115 void BackgroundDatabaseChild::ReleaseDOMObject() {
   1116  AssertIsOnOwningThread();
   1117  MOZ_ASSERT(mTemporaryStrongDatabase);
   1118  mTemporaryStrongDatabase->AssertIsOnOwningThread();
   1119  MOZ_ASSERT(mOpenRequestActor);
   1120  MOZ_ASSERT(mDatabase == mTemporaryStrongDatabase);
   1121 
   1122  mOpenRequestActor->SetDatabaseActor(nullptr);
   1123 
   1124  mOpenRequestActor = nullptr;
   1125 
   1126  // This may be the final reference to the IDBDatabase object so we may end up
   1127  // calling SendDeleteMeInternal() here. Make sure everything is cleaned up
   1128  // properly before proceeding.
   1129  mTemporaryStrongDatabase = nullptr;
   1130 
   1131  // XXX Why isn't mDatabase set to nullptr here?
   1132 }
   1133 
   1134 void BackgroundDatabaseChild::ActorDestroy(ActorDestroyReason aWhy) {
   1135  AssertIsOnOwningThread();
   1136 
   1137  MaybeCollectGarbageOnIPCMessage();
   1138 
   1139  if (mDatabase) {
   1140    mDatabase->ClearBackgroundActor();
   1141 #ifdef DEBUG
   1142    mDatabase = nullptr;
   1143 #endif
   1144  }
   1145 }
   1146 
   1147 PBackgroundIDBDatabaseFileChild*
   1148 BackgroundDatabaseChild::AllocPBackgroundIDBDatabaseFileChild(
   1149    const IPCBlob& aIPCBlob) {
   1150  MOZ_CRASH("PBackgroundIDBFileChild actors should be manually constructed!");
   1151 }
   1152 
   1153 bool BackgroundDatabaseChild::DeallocPBackgroundIDBDatabaseFileChild(
   1154    PBackgroundIDBDatabaseFileChild* aActor) const {
   1155  AssertIsOnOwningThread();
   1156  MOZ_ASSERT(aActor);
   1157 
   1158  delete aActor;
   1159  return true;
   1160 }
   1161 
   1162 already_AddRefed<PBackgroundIDBVersionChangeTransactionChild>
   1163 BackgroundDatabaseChild::AllocPBackgroundIDBVersionChangeTransactionChild(
   1164    const uint64_t aCurrentVersion, const uint64_t aRequestedVersion,
   1165    const int64_t aNextObjectStoreId, const int64_t aNextIndexId) {
   1166  AssertIsOnOwningThread();
   1167 
   1168  return RefPtr{new BackgroundVersionChangeTransactionChild(
   1169                    mOpenRequestActor->GetOpenDBRequest())}
   1170      .forget();
   1171 }
   1172 
   1173 mozilla::ipc::IPCResult
   1174 BackgroundDatabaseChild::RecvPBackgroundIDBVersionChangeTransactionConstructor(
   1175    PBackgroundIDBVersionChangeTransactionChild* aActor,
   1176    const uint64_t& aCurrentVersion, const uint64_t& aRequestedVersion,
   1177    const int64_t& aNextObjectStoreId, const int64_t& aNextIndexId) {
   1178  AssertIsOnOwningThread();
   1179  MOZ_ASSERT(aActor);
   1180  MOZ_ASSERT(mOpenRequestActor);
   1181 
   1182  MaybeCollectGarbageOnIPCMessage();
   1183 
   1184  auto* const actor =
   1185      static_cast<BackgroundVersionChangeTransactionChild*>(aActor);
   1186 
   1187  if (!EnsureDOMObject()) {
   1188    NS_WARNING("Factory is already disconnected from global");
   1189 
   1190    actor->SendDeleteMeInternal(true);
   1191 
   1192    // XXX This is a hack to ensure that transaction/request serial numbers stay
   1193    // in sync between parent and child. Actually, it might be better to create
   1194    // an IDBTransaction in the child and abort that.
   1195    (void)mozilla::ipc::BackgroundChildImpl::GetThreadLocalForCurrentThread()
   1196        ->mIndexedDBThreadLocal->NextTransactionSN(
   1197            IDBTransaction::Mode::VersionChange);
   1198    (void)IDBRequest::NextSerialNumber();
   1199 
   1200    // No reason to IPC_FAIL here.
   1201    return IPC_OK();
   1202  }
   1203 
   1204  MOZ_ASSERT(!mDatabase->IsInvalidated());
   1205 
   1206  // XXX NotNull might encapsulate this
   1207  const auto request =
   1208      WrapNotNullUnchecked(RefPtr{mOpenRequestActor->GetOpenDBRequest().get()});
   1209 
   1210  SafeRefPtr<IDBTransaction> transaction = IDBTransaction::CreateVersionChange(
   1211      mDatabase, actor, request, aNextObjectStoreId, aNextIndexId);
   1212  MOZ_ASSERT(transaction);
   1213 
   1214  transaction->AssertIsOnOwningThread();
   1215 
   1216  actor->SetDOMTransaction(transaction.clonePtr());
   1217 
   1218  const auto database = WrapNotNull(mDatabase);
   1219 
   1220  database->EnterSetVersionTransaction(aRequestedVersion);
   1221 
   1222  request->SetTransaction(transaction.clonePtr());
   1223 
   1224  RefPtr<Event> upgradeNeededEvent = IDBVersionChangeEvent::Create(
   1225      request.get(), nsDependentString(kUpgradeNeededEventType),
   1226      aCurrentVersion, aRequestedVersion);
   1227  MOZ_ASSERT(upgradeNeededEvent);
   1228 
   1229  SetResultAndDispatchSuccessEvent(
   1230      WrapNotNullUnchecked<RefPtr<IDBRequest>>(request.get()), transaction,
   1231      *database, std::move(upgradeNeededEvent));
   1232 
   1233  return IPC_OK();
   1234 }
   1235 
   1236 mozilla::ipc::IPCResult BackgroundDatabaseChild::RecvVersionChange(
   1237    const uint64_t aOldVersion, const Maybe<uint64_t> aNewVersion) {
   1238  AssertIsOnOwningThread();
   1239 
   1240  MaybeCollectGarbageOnIPCMessage();
   1241 
   1242  if (!mDatabase || mDatabase->IsClosed()) {
   1243    return IPC_OK();
   1244  }
   1245 
   1246  RefPtr<IDBDatabase> kungFuDeathGrip = mDatabase;
   1247 
   1248  // Handle bfcache'd windows.
   1249  if (nsGlobalWindowInner* owner = kungFuDeathGrip->GetOwnerWindow()) {
   1250    // The database must be closed if the window is already frozen.
   1251    bool shouldAbortAndClose = owner->IsFrozen();
   1252 
   1253    // Anything in the bfcache has to be evicted and then we have to close the
   1254    // database also.
   1255    if (owner->RemoveFromBFCacheSync()) {
   1256      shouldAbortAndClose = true;
   1257    }
   1258 
   1259    if (shouldAbortAndClose) {
   1260      // Invalidate() doesn't close the database in the parent, so we have
   1261      // to call Close() and AbortTransactions() manually.
   1262      kungFuDeathGrip->AbortTransactions(/* aShouldWarn */ false);
   1263      kungFuDeathGrip->Close();
   1264      return IPC_OK();
   1265    }
   1266  }
   1267 
   1268  // Otherwise fire a versionchange event.
   1269  const nsDependentString type(kVersionChangeEventType);
   1270 
   1271  RefPtr<Event> versionChangeEvent;
   1272 
   1273  if (aNewVersion.isNothing()) {
   1274    versionChangeEvent =
   1275        IDBVersionChangeEvent::Create(kungFuDeathGrip, type, aOldVersion);
   1276    MOZ_ASSERT(versionChangeEvent);
   1277  } else {
   1278    versionChangeEvent = IDBVersionChangeEvent::Create(
   1279        kungFuDeathGrip, type, aOldVersion, aNewVersion.value());
   1280    MOZ_ASSERT(versionChangeEvent);
   1281  }
   1282 
   1283  IDB_LOG_MARK("Child : Firing \"versionchange\" event",
   1284               "C: IDBDatabase \"versionchange\" event", IDB_LOG_ID_STRING());
   1285 
   1286  IgnoredErrorResult rv;
   1287  kungFuDeathGrip->DispatchEvent(*versionChangeEvent, rv);
   1288  if (rv.Failed()) {
   1289    NS_WARNING("Failed to dispatch event!");
   1290  }
   1291 
   1292  if (!kungFuDeathGrip->IsClosed()) {
   1293    SendBlocked();
   1294  }
   1295 
   1296  return IPC_OK();
   1297 }
   1298 
   1299 mozilla::ipc::IPCResult BackgroundDatabaseChild::RecvInvalidate() {
   1300  AssertIsOnOwningThread();
   1301 
   1302  MaybeCollectGarbageOnIPCMessage();
   1303 
   1304  if (mDatabase) {
   1305    mDatabase->Invalidate();
   1306  } else {
   1307    mPendingInvalidate = true;
   1308  }
   1309 
   1310  return IPC_OK();
   1311 }
   1312 
   1313 mozilla::ipc::IPCResult
   1314 BackgroundDatabaseChild::RecvCloseAfterInvalidationComplete() {
   1315  AssertIsOnOwningThread();
   1316 
   1317  MaybeCollectGarbageOnIPCMessage();
   1318 
   1319  if (mDatabase) {
   1320    mDatabase->DispatchTrustedEvent(nsDependentString(kCloseEventType));
   1321  }
   1322 
   1323  return IPC_OK();
   1324 }
   1325 
   1326 /*******************************************************************************
   1327 * BackgroundTransactionBase
   1328 ******************************************************************************/
   1329 
   1330 BackgroundTransactionBase::BackgroundTransactionBase(
   1331    SafeRefPtr<IDBTransaction> aTransaction)
   1332    : mTemporaryStrongTransaction(std::move(aTransaction)),
   1333      mTransaction(mTemporaryStrongTransaction.unsafeGetRawPtr()) {
   1334  MOZ_ASSERT(mTransaction);
   1335  mTransaction->AssertIsOnOwningThread();
   1336 
   1337  MOZ_COUNT_CTOR(BackgroundTransactionBase);
   1338 }
   1339 
   1340 #ifdef DEBUG
   1341 
   1342 void BackgroundTransactionBase::AssertIsOnOwningThread() const {
   1343  MOZ_ASSERT(mTransaction);
   1344  mTransaction->AssertIsOnOwningThread();
   1345 }
   1346 
   1347 #endif  // DEBUG
   1348 
   1349 void BackgroundTransactionBase::NoteActorDestroyed() {
   1350  AssertIsOnOwningThread();
   1351  MOZ_ASSERT_IF(mTemporaryStrongTransaction, mTransaction);
   1352 
   1353  if (mTransaction) {
   1354    mTransaction->ClearBackgroundActor();
   1355 
   1356    // Normally this would be DEBUG-only but NoteActorDestroyed is also called
   1357    // from SendDeleteMeInternal. In that case we're going to receive an actual
   1358    // ActorDestroy call later and we don't want to touch a dead object.
   1359    mTemporaryStrongTransaction = nullptr;
   1360    mTransaction = nullptr;
   1361  }
   1362 }
   1363 
   1364 void BackgroundTransactionBase::SetDOMTransaction(
   1365    SafeRefPtr<IDBTransaction> aTransaction) {
   1366  AssertIsOnOwningThread();
   1367  MOZ_ASSERT(aTransaction);
   1368  aTransaction->AssertIsOnOwningThread();
   1369  MOZ_ASSERT(!mTemporaryStrongTransaction);
   1370  MOZ_ASSERT(!mTransaction);
   1371 
   1372  mTemporaryStrongTransaction = std::move(aTransaction);
   1373  mTransaction = mTemporaryStrongTransaction.unsafeGetRawPtr();
   1374 }
   1375 
   1376 void BackgroundTransactionBase::NoteComplete() {
   1377  AssertIsOnOwningThread();
   1378  MOZ_ASSERT_IF(mTransaction, mTemporaryStrongTransaction);
   1379 
   1380  mTemporaryStrongTransaction = nullptr;
   1381 }
   1382 
   1383 /*******************************************************************************
   1384 * BackgroundTransactionChild
   1385 ******************************************************************************/
   1386 
   1387 BackgroundTransactionChild::BackgroundTransactionChild(
   1388    SafeRefPtr<IDBTransaction> aTransaction)
   1389    : BackgroundTransactionBase(std::move(aTransaction)) {
   1390  MOZ_COUNT_CTOR(indexedDB::BackgroundTransactionChild);
   1391 }
   1392 
   1393 BackgroundTransactionChild::~BackgroundTransactionChild() {
   1394  MOZ_COUNT_DTOR(indexedDB::BackgroundTransactionChild);
   1395 }
   1396 
   1397 #ifdef DEBUG
   1398 
   1399 void BackgroundTransactionChild::AssertIsOnOwningThread() const {
   1400  static_cast<BackgroundDatabaseChild*>(Manager())->AssertIsOnOwningThread();
   1401 }
   1402 
   1403 #endif  // DEBUG
   1404 
   1405 void BackgroundTransactionChild::SendDeleteMeInternal() {
   1406  AssertIsOnOwningThread();
   1407 
   1408  if (mTransaction) {
   1409    NoteActorDestroyed();
   1410 
   1411    MOZ_ALWAYS_TRUE(PBackgroundIDBTransactionChild::SendDeleteMe());
   1412  }
   1413 }
   1414 
   1415 void BackgroundTransactionChild::ActorDestroy(ActorDestroyReason aWhy) {
   1416  AssertIsOnOwningThread();
   1417 
   1418  MaybeCollectGarbageOnIPCMessage();
   1419 
   1420  NoteActorDestroyed();
   1421 }
   1422 
   1423 mozilla::ipc::IPCResult BackgroundTransactionChild::RecvComplete(
   1424    const nsresult aResult) {
   1425  AssertIsOnOwningThread();
   1426  MOZ_ASSERT(mTransaction);
   1427 
   1428  MaybeCollectGarbageOnIPCMessage();
   1429 
   1430  mTransaction->FireCompleteOrAbortEvents(aResult);
   1431 
   1432  NoteComplete();
   1433  return IPC_OK();
   1434 }
   1435 
   1436 PBackgroundIDBRequestChild*
   1437 BackgroundTransactionChild::AllocPBackgroundIDBRequestChild(
   1438    const int64_t& aRequestId, const RequestParams& aParams) {
   1439  MOZ_CRASH(
   1440      "PBackgroundIDBRequestChild actors should be manually "
   1441      "constructed!");
   1442 }
   1443 
   1444 bool BackgroundTransactionChild::DeallocPBackgroundIDBRequestChild(
   1445    PBackgroundIDBRequestChild* aActor) {
   1446  MOZ_ASSERT(aActor);
   1447 
   1448  delete static_cast<BackgroundRequestChild*>(aActor);
   1449  return true;
   1450 }
   1451 
   1452 PBackgroundIDBCursorChild*
   1453 BackgroundTransactionChild::AllocPBackgroundIDBCursorChild(
   1454    const int64_t& aRequestId, const OpenCursorParams& aParams) {
   1455  AssertIsOnOwningThread();
   1456 
   1457  MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
   1458 }
   1459 
   1460 bool BackgroundTransactionChild::DeallocPBackgroundIDBCursorChild(
   1461    PBackgroundIDBCursorChild* aActor) {
   1462  MOZ_ASSERT(aActor);
   1463 
   1464  delete aActor;
   1465  return true;
   1466 }
   1467 
   1468 /*******************************************************************************
   1469 * BackgroundVersionChangeTransactionChild
   1470 ******************************************************************************/
   1471 
   1472 BackgroundVersionChangeTransactionChild::
   1473    BackgroundVersionChangeTransactionChild(IDBOpenDBRequest* aOpenDBRequest)
   1474    : mOpenDBRequest(aOpenDBRequest) {
   1475  MOZ_ASSERT(aOpenDBRequest);
   1476  aOpenDBRequest->AssertIsOnOwningThread();
   1477 
   1478  MOZ_COUNT_CTOR(indexedDB::BackgroundVersionChangeTransactionChild);
   1479 }
   1480 
   1481 BackgroundVersionChangeTransactionChild::
   1482    ~BackgroundVersionChangeTransactionChild() {
   1483  AssertIsOnOwningThread();
   1484 
   1485  MOZ_COUNT_DTOR(indexedDB::BackgroundVersionChangeTransactionChild);
   1486 }
   1487 
   1488 #ifdef DEBUG
   1489 
   1490 void BackgroundVersionChangeTransactionChild::AssertIsOnOwningThread() const {
   1491  static_cast<BackgroundDatabaseChild*>(Manager())->AssertIsOnOwningThread();
   1492 }
   1493 
   1494 #endif  // DEBUG
   1495 
   1496 void BackgroundVersionChangeTransactionChild::SendDeleteMeInternal(
   1497    bool aFailedConstructor) {
   1498  AssertIsOnOwningThread();
   1499 
   1500  if (mTransaction || aFailedConstructor) {
   1501    NoteActorDestroyed();
   1502 
   1503    MOZ_ALWAYS_TRUE(
   1504        PBackgroundIDBVersionChangeTransactionChild::SendDeleteMe());
   1505  }
   1506 }
   1507 
   1508 void BackgroundVersionChangeTransactionChild::ActorDestroy(
   1509    ActorDestroyReason aWhy) {
   1510  AssertIsOnOwningThread();
   1511 
   1512  MaybeCollectGarbageOnIPCMessage();
   1513 
   1514  mOpenDBRequest = nullptr;
   1515 
   1516  NoteActorDestroyed();
   1517 }
   1518 
   1519 mozilla::ipc::IPCResult BackgroundVersionChangeTransactionChild::RecvComplete(
   1520    const nsresult aResult) {
   1521  AssertIsOnOwningThread();
   1522 
   1523  MaybeCollectGarbageOnIPCMessage();
   1524 
   1525  if (!mTransaction) {
   1526    return IPC_OK();
   1527  }
   1528 
   1529  MOZ_ASSERT(mOpenDBRequest);
   1530 
   1531  IDBDatabase* database = mTransaction->Database();
   1532  MOZ_ASSERT(database);
   1533 
   1534  database->ExitSetVersionTransaction();
   1535 
   1536  if (NS_FAILED(aResult)) {
   1537    database->Close();
   1538  }
   1539 
   1540  RefPtr<IDBOpenDBRequest> request = mOpenDBRequest;
   1541  MOZ_ASSERT(request);
   1542 
   1543  mTransaction->FireCompleteOrAbortEvents(aResult);
   1544 
   1545  request->SetTransaction(nullptr);
   1546  request = nullptr;
   1547 
   1548  mOpenDBRequest = nullptr;
   1549 
   1550  NoteComplete();
   1551  return IPC_OK();
   1552 }
   1553 
   1554 PBackgroundIDBRequestChild*
   1555 BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBRequestChild(
   1556    const int64_t& aRequestId, const RequestParams& aParams) {
   1557  MOZ_CRASH(
   1558      "PBackgroundIDBRequestChild actors should be manually "
   1559      "constructed!");
   1560 }
   1561 
   1562 bool BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBRequestChild(
   1563    PBackgroundIDBRequestChild* aActor) {
   1564  MOZ_ASSERT(aActor);
   1565 
   1566  delete static_cast<BackgroundRequestChild*>(aActor);
   1567  return true;
   1568 }
   1569 
   1570 PBackgroundIDBCursorChild*
   1571 BackgroundVersionChangeTransactionChild::AllocPBackgroundIDBCursorChild(
   1572    const int64_t& aRequestId, const OpenCursorParams& aParams) {
   1573  AssertIsOnOwningThread();
   1574 
   1575  MOZ_CRASH("PBackgroundIDBCursorChild actors should be manually constructed!");
   1576 }
   1577 
   1578 bool BackgroundVersionChangeTransactionChild::DeallocPBackgroundIDBCursorChild(
   1579    PBackgroundIDBCursorChild* aActor) {
   1580  MOZ_ASSERT(aActor);
   1581 
   1582  delete aActor;
   1583  return true;
   1584 }
   1585 
   1586 /*******************************************************************************
   1587 * BackgroundRequestChild
   1588 ******************************************************************************/
   1589 
   1590 BackgroundRequestChild::BackgroundRequestChild(
   1591    MovingNotNull<RefPtr<IDBRequest>> aRequest)
   1592    : BackgroundRequestChildBase(std::move(aRequest)),
   1593      mTransaction(mRequest->AcquireTransaction()),
   1594      mRunningPreprocessHelpers(0),
   1595      mCurrentCloneDataIndex(0),
   1596      mPreprocessResultCode(NS_OK),
   1597      mGetAll(false) {
   1598  MOZ_ASSERT(mTransaction);
   1599  mTransaction->AssertIsOnOwningThread();
   1600 
   1601  MOZ_COUNT_CTOR(indexedDB::BackgroundRequestChild);
   1602 }
   1603 
   1604 BackgroundRequestChild::~BackgroundRequestChild() {
   1605  AssertIsOnOwningThread();
   1606  MOZ_ASSERT(!mTransaction);
   1607 
   1608  MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChild);
   1609 }
   1610 
   1611 void BackgroundRequestChild::MaybeSendContinue() {
   1612  AssertIsOnOwningThread();
   1613  MOZ_ASSERT(mRunningPreprocessHelpers > 0);
   1614 
   1615  if (--mRunningPreprocessHelpers == 0) {
   1616    PreprocessResponse response;
   1617 
   1618    if (NS_SUCCEEDED(mPreprocessResultCode)) {
   1619      if (mGetAll) {
   1620        response = ObjectStoreGetAllPreprocessResponse();
   1621      } else {
   1622        response = ObjectStoreGetPreprocessResponse();
   1623      }
   1624    } else {
   1625      response = mPreprocessResultCode;
   1626    }
   1627 
   1628    MOZ_ALWAYS_TRUE(SendContinue(response));
   1629  }
   1630 }
   1631 
   1632 void BackgroundRequestChild::OnPreprocessFinished(
   1633    uint32_t aCloneDataIndex, UniquePtr<JSStructuredCloneData> aCloneData) {
   1634  AssertIsOnOwningThread();
   1635  MOZ_ASSERT(aCloneDataIndex < mCloneInfos.Length());
   1636  MOZ_ASSERT(aCloneData);
   1637 
   1638  auto& cloneInfo = mCloneInfos[aCloneDataIndex];
   1639  MOZ_ASSERT(cloneInfo.mPreprocessHelper);
   1640  MOZ_ASSERT(!cloneInfo.mCloneData);
   1641 
   1642  cloneInfo.mCloneData = std::move(aCloneData);
   1643 
   1644  MaybeSendContinue();
   1645 
   1646  cloneInfo.mPreprocessHelper = nullptr;
   1647 }
   1648 
   1649 void BackgroundRequestChild::OnPreprocessFailed(uint32_t aCloneDataIndex,
   1650                                                nsresult aErrorCode) {
   1651  AssertIsOnOwningThread();
   1652  MOZ_ASSERT(aCloneDataIndex < mCloneInfos.Length());
   1653  MOZ_ASSERT(NS_FAILED(aErrorCode));
   1654 
   1655  auto& cloneInfo = mCloneInfos[aCloneDataIndex];
   1656  MOZ_ASSERT(cloneInfo.mPreprocessHelper);
   1657  MOZ_ASSERT(!cloneInfo.mCloneData);
   1658 
   1659  if (NS_SUCCEEDED(mPreprocessResultCode)) {
   1660    mPreprocessResultCode = aErrorCode;
   1661  }
   1662 
   1663  MaybeSendContinue();
   1664 
   1665  cloneInfo.mPreprocessHelper = nullptr;
   1666 }
   1667 
   1668 UniquePtr<JSStructuredCloneData> BackgroundRequestChild::GetNextCloneData() {
   1669  AssertIsOnOwningThread();
   1670  MOZ_ASSERT(mCurrentCloneDataIndex < mCloneInfos.Length());
   1671  MOZ_ASSERT(mCloneInfos[mCurrentCloneDataIndex].mCloneData);
   1672 
   1673  return std::move(mCloneInfos[mCurrentCloneDataIndex++].mCloneData);
   1674 }
   1675 
   1676 void BackgroundRequestChild::HandleResponse(nsresult aResponse) {
   1677  AssertIsOnOwningThread();
   1678  MOZ_ASSERT(NS_FAILED(aResponse));
   1679  MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
   1680  MOZ_ASSERT(mTransaction);
   1681 
   1682  DispatchErrorEvent(mRequest, aResponse, mTransaction.clonePtr());
   1683 }
   1684 
   1685 void BackgroundRequestChild::HandleResponse(const Key& aResponse) {
   1686  AssertIsOnOwningThread();
   1687 
   1688  SetResultAndDispatchSuccessEvent(mRequest, AcquireTransaction(), aResponse);
   1689 }
   1690 
   1691 void BackgroundRequestChild::HandleResponse(const nsTArray<Key>& aResponse) {
   1692  AssertIsOnOwningThread();
   1693 
   1694  SetResultAndDispatchSuccessEvent(mRequest, AcquireTransaction(), aResponse);
   1695 }
   1696 
   1697 void BackgroundRequestChild::HandleResponse(
   1698    SerializedStructuredCloneReadInfo&& aResponse) {
   1699  AssertIsOnOwningThread();
   1700 
   1701  if (!mTransaction->Database()->GetOwnerGlobal()) {
   1702    // Ignore the response, since we have already been disconnected from the
   1703    // global.
   1704    return;
   1705  }
   1706 
   1707  auto cloneReadInfo = DeserializeStructuredCloneReadInfo(
   1708      std::move(aResponse), mTransaction->Database(),
   1709      [this] { return std::move(*GetNextCloneData()); });
   1710 
   1711  SetResultAndDispatchSuccessEvent(mRequest, AcquireTransaction(),
   1712                                   cloneReadInfo);
   1713 }
   1714 
   1715 void BackgroundRequestChild::HandleResponse(
   1716    nsTArray<SerializedStructuredCloneReadInfo>&& aResponse) {
   1717  AssertIsOnOwningThread();
   1718 
   1719  if (!mTransaction->Database()->GetOwnerGlobal()) {
   1720    // Ignore the response, since we have already been disconnected from the
   1721    // global.
   1722    return;
   1723  }
   1724 
   1725  nsTArray<StructuredCloneReadInfoChild> cloneReadInfos;
   1726 
   1727  QM_TRY(OkIf(cloneReadInfos.SetCapacity(aResponse.Length(), fallible)),
   1728         QM_VOID, ([&aResponse, this](const auto) {
   1729           // Since we are under memory pressure, release aResponse early.
   1730           aResponse.Clear();
   1731 
   1732           DispatchErrorEvent(mRequest, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR,
   1733                              AcquireTransaction());
   1734 
   1735           MOZ_ASSERT(mTransaction->IsAborted());
   1736         }));
   1737 
   1738  std::transform(std::make_move_iterator(aResponse.begin()),
   1739                 std::make_move_iterator(aResponse.end()),
   1740                 MakeBackInserter(cloneReadInfos),
   1741                 [database = mTransaction->Database(), this](
   1742                     SerializedStructuredCloneReadInfo&& serializedCloneInfo) {
   1743                   return DeserializeStructuredCloneReadInfo(
   1744                       std::move(serializedCloneInfo), database,
   1745                       [this] { return std::move(*GetNextCloneData()); });
   1746                 });
   1747 
   1748  SetResultAndDispatchSuccessEvent(mRequest, AcquireTransaction(),
   1749                                   cloneReadInfos);
   1750 }
   1751 
   1752 void BackgroundRequestChild::HandleResponse(JS::Handle<JS::Value> aResponse) {
   1753  AssertIsOnOwningThread();
   1754 
   1755  SetResultAndDispatchSuccessEvent(
   1756      mRequest, AcquireTransaction(),
   1757      const_cast<const JS::Handle<JS::Value>&>(aResponse));
   1758 }
   1759 
   1760 void BackgroundRequestChild::HandleResponse(const uint64_t aResponse) {
   1761  AssertIsOnOwningThread();
   1762 
   1763  SetResultAndDispatchSuccessEvent(mRequest, AcquireTransaction(), aResponse);
   1764 }
   1765 
   1766 nsresult BackgroundRequestChild::HandlePreprocess(
   1767    const PreprocessInfo& aPreprocessInfo) {
   1768  return HandlePreprocessInternal(
   1769      AutoTArray<PreprocessInfo, 1>{aPreprocessInfo});
   1770 }
   1771 
   1772 nsresult BackgroundRequestChild::HandlePreprocess(
   1773    const nsTArray<PreprocessInfo>& aPreprocessInfos) {
   1774  AssertIsOnOwningThread();
   1775  mGetAll = true;
   1776 
   1777  return HandlePreprocessInternal(aPreprocessInfos);
   1778 }
   1779 
   1780 nsresult BackgroundRequestChild::HandlePreprocessInternal(
   1781    const nsTArray<PreprocessInfo>& aPreprocessInfos) {
   1782  AssertIsOnOwningThread();
   1783 
   1784  IDBDatabase* database = mTransaction->Database();
   1785 
   1786  const uint32_t count = aPreprocessInfos.Length();
   1787 
   1788  mCloneInfos.SetLength(count);
   1789 
   1790  // TODO: Since we use the stream transport service, this can spawn 25 threads
   1791  //       and has the potential to cause some annoying browser hiccups.
   1792  //       Consider using a single thread or a very small threadpool.
   1793  for (uint32_t index = 0; index < count; index++) {
   1794    const PreprocessInfo& preprocessInfo = aPreprocessInfos[index];
   1795 
   1796    const auto files =
   1797        DeserializeStructuredCloneFiles(database, preprocessInfo.files(),
   1798                                        /* aForPreprocess */ true);
   1799 
   1800    MOZ_ASSERT(files.Length() == 1);
   1801 
   1802    auto& preprocessHelper = mCloneInfos[index].mPreprocessHelper;
   1803    preprocessHelper = MakeRefPtr<PreprocessHelper>(index, this);
   1804 
   1805    nsresult rv = preprocessHelper->Init(files[0]);
   1806    if (NS_WARN_IF(NS_FAILED(rv))) {
   1807      return rv;
   1808    }
   1809 
   1810    rv = preprocessHelper->Dispatch();
   1811    if (NS_WARN_IF(NS_FAILED(rv))) {
   1812      return rv;
   1813    }
   1814 
   1815    mRunningPreprocessHelpers++;
   1816  }
   1817 
   1818  return NS_OK;
   1819 }
   1820 
   1821 void BackgroundRequestChild::ActorDestroy(ActorDestroyReason aWhy) {
   1822  AssertIsOnOwningThread();
   1823 
   1824  MaybeCollectGarbageOnIPCMessage();
   1825 
   1826  for (auto& cloneInfo : mCloneInfos) {
   1827    const auto& preprocessHelper = cloneInfo.mPreprocessHelper;
   1828 
   1829    if (preprocessHelper) {
   1830      preprocessHelper->ClearActor();
   1831    }
   1832  }
   1833  mCloneInfos.Clear();
   1834 
   1835  if (mTransaction) {
   1836    mTransaction->AssertIsOnOwningThread();
   1837 
   1838    mTransaction->OnRequestFinished(/* aRequestCompletedSuccessfully */
   1839                                    aWhy == Deletion);
   1840 #ifdef DEBUG
   1841    mTransaction = nullptr;
   1842 #endif
   1843  }
   1844 }
   1845 
   1846 mozilla::ipc::IPCResult BackgroundRequestChild::Recv__delete__(
   1847    RequestResponse&& aResponse) {
   1848  AssertIsOnOwningThread();
   1849  MOZ_ASSERT(mTransaction);
   1850 
   1851  MaybeCollectGarbageOnIPCMessage();
   1852 
   1853  if (mTransaction->IsAborted()) {
   1854    // Always fire an "error" event with ABORT_ERR if the transaction was
   1855    // aborted, even if the request succeeded or failed with another error.
   1856    HandleResponse(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
   1857  } else {
   1858    switch (aResponse.type()) {
   1859      case RequestResponse::Tnsresult:
   1860        HandleResponse(aResponse.get_nsresult());
   1861        break;
   1862 
   1863      case RequestResponse::TObjectStoreAddResponse:
   1864        HandleResponse(aResponse.get_ObjectStoreAddResponse().key());
   1865        break;
   1866 
   1867      case RequestResponse::TObjectStorePutResponse:
   1868        HandleResponse(aResponse.get_ObjectStorePutResponse().key());
   1869        break;
   1870 
   1871      case RequestResponse::TObjectStoreGetResponse:
   1872        HandleResponse(
   1873            std::move(aResponse.get_ObjectStoreGetResponse().cloneInfo()));
   1874        break;
   1875 
   1876      case RequestResponse::TObjectStoreGetKeyResponse:
   1877        HandleResponse(aResponse.get_ObjectStoreGetKeyResponse().key());
   1878        break;
   1879 
   1880      case RequestResponse::TObjectStoreGetAllResponse:
   1881        HandleResponse(
   1882            std::move(aResponse.get_ObjectStoreGetAllResponse().cloneInfos()));
   1883        break;
   1884 
   1885      case RequestResponse::TObjectStoreGetAllKeysResponse:
   1886        HandleResponse(aResponse.get_ObjectStoreGetAllKeysResponse().keys());
   1887        break;
   1888 
   1889      case RequestResponse::TObjectStoreDeleteResponse:
   1890      case RequestResponse::TObjectStoreClearResponse:
   1891        HandleResponse(JS::UndefinedHandleValue);
   1892        break;
   1893 
   1894      case RequestResponse::TObjectStoreCountResponse:
   1895        HandleResponse(aResponse.get_ObjectStoreCountResponse().count());
   1896        break;
   1897 
   1898      case RequestResponse::TIndexGetResponse:
   1899        HandleResponse(std::move(aResponse.get_IndexGetResponse().cloneInfo()));
   1900        break;
   1901 
   1902      case RequestResponse::TIndexGetKeyResponse:
   1903        HandleResponse(aResponse.get_IndexGetKeyResponse().key());
   1904        break;
   1905 
   1906      case RequestResponse::TIndexGetAllResponse:
   1907        HandleResponse(
   1908            std::move(aResponse.get_IndexGetAllResponse().cloneInfos()));
   1909        break;
   1910 
   1911      case RequestResponse::TIndexGetAllKeysResponse:
   1912        HandleResponse(aResponse.get_IndexGetAllKeysResponse().keys());
   1913        break;
   1914 
   1915      case RequestResponse::TIndexCountResponse:
   1916        HandleResponse(aResponse.get_IndexCountResponse().count());
   1917        break;
   1918 
   1919      default:
   1920        return IPC_FAIL(this, "Unknown response type!");
   1921    }
   1922  }
   1923 
   1924  mTransaction->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
   1925 
   1926  // Null this out so that we don't try to call OnRequestFinished() again in
   1927  // ActorDestroy.
   1928  mTransaction = nullptr;
   1929 
   1930  return IPC_OK();
   1931 }
   1932 
   1933 mozilla::ipc::IPCResult BackgroundRequestChild::RecvPreprocess(
   1934    const PreprocessParams& aParams) {
   1935  AssertIsOnOwningThread();
   1936  MOZ_ASSERT(mTransaction);
   1937 
   1938  MaybeCollectGarbageOnIPCMessage();
   1939 
   1940  nsresult rv;
   1941 
   1942  switch (aParams.type()) {
   1943    case PreprocessParams::TObjectStoreGetPreprocessParams: {
   1944      const auto& params = aParams.get_ObjectStoreGetPreprocessParams();
   1945 
   1946      rv = HandlePreprocess(params.preprocessInfo());
   1947 
   1948      break;
   1949    }
   1950 
   1951    case PreprocessParams::TObjectStoreGetAllPreprocessParams: {
   1952      const auto& params = aParams.get_ObjectStoreGetAllPreprocessParams();
   1953 
   1954      rv = HandlePreprocess(params.preprocessInfos());
   1955 
   1956      break;
   1957    }
   1958 
   1959    default:
   1960      return IPC_FAIL(this, "Unknown params type!");
   1961  }
   1962 
   1963  if (NS_WARN_IF(NS_FAILED(rv))) {
   1964    QM_WARNONLY_TRY(OkIf(SendContinue(rv)));
   1965  }
   1966 
   1967  return IPC_OK();
   1968 }
   1969 
   1970 nsresult BackgroundRequestChild::PreprocessHelper::Init(
   1971    const StructuredCloneFileChild& aFile) {
   1972  AssertIsOnOwningThread();
   1973  MOZ_ASSERT(aFile.HasBlob());
   1974  MOZ_ASSERT(aFile.Type() == StructuredCloneFileBase::eStructuredClone);
   1975  MOZ_ASSERT(mState == State::Initial);
   1976 
   1977  // The stream transport service is used for asynchronous processing. It has a
   1978  // threadpool with a high cap of 25 threads. Fortunately, the service can be
   1979  // used on workers too.
   1980  nsCOMPtr<nsIEventTarget> target =
   1981      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   1982  MOZ_ASSERT(target);
   1983 
   1984  // We use a TaskQueue here in order to be sure that the events are dispatched
   1985  // in the correct order. This is not guaranteed in case we use the I/O thread
   1986  // directly.
   1987  mTaskQueue = TaskQueue::Create(target.forget(), "BackgroundRequestChild");
   1988 
   1989  ErrorResult errorResult;
   1990 
   1991  nsCOMPtr<nsIInputStream> stream;
   1992  // XXX After Bug 1620560, MutableBlob is not needed here anymore.
   1993  aFile.MutableBlob().CreateInputStream(getter_AddRefs(stream), errorResult);
   1994  if (NS_WARN_IF(errorResult.Failed())) {
   1995    return errorResult.StealNSResult();
   1996  }
   1997 
   1998  mStream = std::move(stream);
   1999 
   2000  mCloneData = MakeUnique<JSStructuredCloneData>(
   2001      JS::StructuredCloneScope::DifferentProcessForIndexedDB);
   2002 
   2003  return NS_OK;
   2004 }
   2005 
   2006 nsresult BackgroundRequestChild::PreprocessHelper::Dispatch() {
   2007  AssertIsOnOwningThread();
   2008  MOZ_ASSERT(mState == State::Initial);
   2009 
   2010  nsresult rv = mTaskQueue->Dispatch(this, NS_DISPATCH_NORMAL);
   2011  if (NS_WARN_IF(NS_FAILED(rv))) {
   2012    return rv;
   2013  }
   2014 
   2015  return NS_OK;
   2016 }
   2017 
   2018 nsresult BackgroundRequestChild::PreprocessHelper::Start() {
   2019  MOZ_ASSERT(!IsOnOwningThread());
   2020  MOZ_ASSERT(mStream);
   2021  MOZ_ASSERT(mState == State::Initial);
   2022 
   2023  nsresult rv;
   2024 
   2025  PRFileDesc* fileDesc = GetFileDescriptorFromStream(mStream);
   2026  if (fileDesc) {
   2027    rv = ProcessStream();
   2028    if (NS_WARN_IF(NS_FAILED(rv))) {
   2029      return rv;
   2030    }
   2031 
   2032    return NS_OK;
   2033  }
   2034 
   2035  mState = State::WaitingForStreamReady;
   2036 
   2037  nsCOMPtr<nsIAsyncFileMetadata> asyncFileMetadata = do_QueryInterface(mStream);
   2038  if (asyncFileMetadata) {
   2039    rv = asyncFileMetadata->AsyncFileMetadataWait(this, mTaskQueue);
   2040    if (NS_WARN_IF(NS_FAILED(rv))) {
   2041      return rv;
   2042    }
   2043 
   2044    return NS_OK;
   2045  }
   2046 
   2047  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mStream);
   2048  if (!asyncStream) {
   2049    return NS_ERROR_NO_INTERFACE;
   2050  }
   2051 
   2052  rv = asyncStream->AsyncWait(this, 0, 0, mTaskQueue);
   2053  if (NS_WARN_IF(NS_FAILED(rv))) {
   2054    return rv;
   2055  }
   2056 
   2057  return NS_OK;
   2058 }
   2059 
   2060 nsresult BackgroundRequestChild::PreprocessHelper::ProcessStream() {
   2061  MOZ_ASSERT(!IsOnOwningThread());
   2062  MOZ_ASSERT(mStream);
   2063  MOZ_ASSERT(mState == State::Initial ||
   2064             mState == State::WaitingForStreamReady);
   2065 
   2066  // We need to get the internal stream (which is an nsFileInputStream) because
   2067  // SnappyUncompressInputStream doesn't support reading from async input
   2068  // streams.
   2069 
   2070  nsCOMPtr<mozIRemoteLazyInputStream> blobInputStream =
   2071      do_QueryInterface(mStream);
   2072  MOZ_ASSERT(blobInputStream);
   2073 
   2074  nsCOMPtr<nsIInputStream> internalInputStream;
   2075  MOZ_ALWAYS_SUCCEEDS(
   2076      blobInputStream->TakeInternalStream(getter_AddRefs(internalInputStream)));
   2077  MOZ_ASSERT(internalInputStream);
   2078 
   2079  QM_TRY(MOZ_TO_RESULT(
   2080      SnappyUncompressStructuredCloneData(*internalInputStream, *mCloneData)));
   2081 
   2082  mState = State::Finishing;
   2083 
   2084  QM_TRY(MOZ_TO_RESULT(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL)));
   2085 
   2086  return NS_OK;
   2087 }
   2088 
   2089 void BackgroundRequestChild::PreprocessHelper::Finish() {
   2090  AssertIsOnOwningThread();
   2091 
   2092  if (mActor) {
   2093    if (NS_SUCCEEDED(mResultCode)) {
   2094      mActor->OnPreprocessFinished(mCloneDataIndex, std::move(mCloneData));
   2095 
   2096      MOZ_ASSERT(!mCloneData);
   2097    } else {
   2098      mActor->OnPreprocessFailed(mCloneDataIndex, mResultCode);
   2099    }
   2100  }
   2101 
   2102  mState = State::Completed;
   2103 }
   2104 
   2105 NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper,
   2106                            DiscardableRunnable, nsIInputStreamCallback,
   2107                            nsIFileMetadataCallback)
   2108 
   2109 NS_IMETHODIMP
   2110 BackgroundRequestChild::PreprocessHelper::Run() {
   2111  nsresult rv;
   2112 
   2113  switch (mState) {
   2114    case State::Initial:
   2115      rv = Start();
   2116      break;
   2117 
   2118    case State::WaitingForStreamReady:
   2119      rv = ProcessStream();
   2120      break;
   2121 
   2122    case State::Finishing:
   2123      Finish();
   2124      return NS_OK;
   2125 
   2126    default:
   2127      MOZ_CRASH("Bad state!");
   2128  }
   2129 
   2130  if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
   2131    if (NS_SUCCEEDED(mResultCode)) {
   2132      mResultCode = rv;
   2133    }
   2134 
   2135    // Must set mState before dispatching otherwise we will race with the owning
   2136    // thread.
   2137    mState = State::Finishing;
   2138 
   2139    if (IsOnOwningThread()) {
   2140      Finish();
   2141    } else {
   2142      MOZ_ALWAYS_SUCCEEDS(
   2143          mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   2144    }
   2145  }
   2146 
   2147  return NS_OK;
   2148 }
   2149 
   2150 NS_IMETHODIMP
   2151 BackgroundRequestChild::PreprocessHelper::OnInputStreamReady(
   2152    nsIAsyncInputStream* aStream) {
   2153  MOZ_ASSERT(!IsOnOwningThread());
   2154  MOZ_ASSERT(mState == State::WaitingForStreamReady);
   2155 
   2156  MOZ_ALWAYS_SUCCEEDS(this->Run());
   2157 
   2158  return NS_OK;
   2159 }
   2160 
   2161 NS_IMETHODIMP
   2162 BackgroundRequestChild::PreprocessHelper::OnFileMetadataReady(
   2163    nsIAsyncFileMetadata* aObject) {
   2164  MOZ_ASSERT(!IsOnOwningThread());
   2165  MOZ_ASSERT(mState == State::WaitingForStreamReady);
   2166 
   2167  MOZ_ALWAYS_SUCCEEDS(this->Run());
   2168 
   2169  return NS_OK;
   2170 }
   2171 
   2172 /*******************************************************************************
   2173 * BackgroundCursorChild
   2174 ******************************************************************************/
   2175 
   2176 BackgroundCursorChildBase::BackgroundCursorChildBase(
   2177    const NotNull<IDBRequest*> aRequest, const Direction aDirection)
   2178    : mRequest(aRequest),
   2179      mTransaction(aRequest->MaybeTransactionRef()),
   2180      mStrongRequest(aRequest),
   2181      mDirection(aDirection) {
   2182  MOZ_ASSERT(mTransaction);
   2183 }
   2184 
   2185 MovingNotNull<RefPtr<IDBRequest>> BackgroundCursorChildBase::AcquireRequest()
   2186    const {
   2187  AssertIsOnOwningThread();
   2188 
   2189  // XXX This could be encapsulated by NotNull
   2190  return WrapNotNullUnchecked(RefPtr{mRequest->get()});
   2191 }
   2192 
   2193 template <IDBCursorType CursorType>
   2194 BackgroundCursorChild<CursorType>::BackgroundCursorChild(
   2195    const NotNull<IDBRequest*> aRequest, SourceType* aSource,
   2196    Direction aDirection)
   2197    : BackgroundCursorChildBase(aRequest, aDirection),
   2198      mSource(WrapNotNull(aSource)),
   2199      mCursor(nullptr),
   2200      mInFlightResponseInvalidationNeeded(false) {
   2201  aSource->AssertIsOnOwningThread();
   2202 
   2203  MOZ_COUNT_CTOR(indexedDB::BackgroundCursorChild<CursorType>);
   2204 }
   2205 
   2206 template <IDBCursorType CursorType>
   2207 BackgroundCursorChild<CursorType>::~BackgroundCursorChild() {
   2208  MOZ_COUNT_DTOR(indexedDB::BackgroundCursorChild<CursorType>);
   2209 }
   2210 
   2211 template <IDBCursorType CursorType>
   2212 SafeRefPtr<BackgroundCursorChild<CursorType>>
   2213 BackgroundCursorChild<CursorType>::SafeRefPtrFromThis() {
   2214  return BackgroundCursorChildBase::SafeRefPtrFromThis()
   2215      .template downcast<BackgroundCursorChild>();
   2216 }
   2217 
   2218 template <IDBCursorType CursorType>
   2219 void BackgroundCursorChild<CursorType>::SendContinueInternal(
   2220    const int64_t aRequestId, const CursorRequestParams& aParams,
   2221    const CursorData<CursorType>& aCurrentData) {
   2222  AssertIsOnOwningThread();
   2223  MOZ_ASSERT(mRequest);
   2224  MOZ_ASSERT(mTransaction);
   2225  MOZ_ASSERT(mCursor);
   2226  MOZ_ASSERT(!mStrongRequest);
   2227  MOZ_ASSERT(!mStrongCursor);
   2228 
   2229  // Make sure all our DOM objects stay alive.
   2230  mStrongCursor = mCursor;
   2231 
   2232  MOZ_ASSERT(GetRequest()->ReadyState() == IDBRequestReadyState::Done);
   2233  GetRequest()->Reset();
   2234 
   2235  mTransaction->OnNewRequest();
   2236 
   2237  CursorRequestParams params = aParams;
   2238  Key currentKey = aCurrentData.mKey;
   2239  Key currentObjectStoreKey;
   2240  // TODO: This is still not nice.
   2241  if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
   2242    currentObjectStoreKey = aCurrentData.mObjectStoreKey;
   2243  }
   2244 
   2245  switch (params.type()) {
   2246    case CursorRequestParams::TContinueParams: {
   2247      const auto& key = params.get_ContinueParams().key();
   2248      if (key.IsUnset()) {
   2249        break;
   2250      }
   2251 
   2252      // Discard cache entries before the target key.
   2253      DiscardCachedResponses(
   2254          [&key, isLocaleAware = mCursor->IsLocaleAware(),
   2255           keyOperator = GetKeyOperator(mDirection),
   2256           transactionSerialNumber = mTransaction->LoggingSerialNumber(),
   2257           requestSerialNumber = GetRequest()->LoggingSerialNumber()](
   2258              const auto& currentCachedResponse) {
   2259            // This duplicates the logic from the parent. We could avoid this
   2260            // duplication if we invalidated the cached records always for any
   2261            // continue-with-key operation, but would lose the benefits of
   2262            // preloading then.
   2263            const auto& cachedSortKey =
   2264                currentCachedResponse.GetSortKey(isLocaleAware);
   2265            const bool discard = !(cachedSortKey.*keyOperator)(key);
   2266            if (discard) {
   2267              IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2268                  "PRELOAD: Continue to key %s, discarding cached key %s/%s",
   2269                  "Continue, discarding%.0s%.0s%.0s", transactionSerialNumber,
   2270                  requestSerialNumber, key.GetBuffer().get(),
   2271                  cachedSortKey.GetBuffer().get(),
   2272                  currentCachedResponse.GetObjectStoreKeyForLogging());
   2273            } else {
   2274              IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2275                  "PRELOAD: Continue to key %s, keeping cached key %s/%s and "
   2276                  "further",
   2277                  "Continue, keeping%.0s%.0s%.0s", transactionSerialNumber,
   2278                  requestSerialNumber, key.GetBuffer().get(),
   2279                  cachedSortKey.GetBuffer().get(),
   2280                  currentCachedResponse.GetObjectStoreKeyForLogging());
   2281            }
   2282 
   2283            return discard;
   2284          });
   2285 
   2286      break;
   2287    }
   2288 
   2289    case CursorRequestParams::TContinuePrimaryKeyParams: {
   2290      if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
   2291        const auto& key = params.get_ContinuePrimaryKeyParams().key();
   2292        const auto& primaryKey =
   2293            params.get_ContinuePrimaryKeyParams().primaryKey();
   2294        if (key.IsUnset() || primaryKey.IsUnset()) {
   2295          break;
   2296        }
   2297 
   2298        // Discard cache entries before the target key.
   2299        DiscardCachedResponses([&key, &primaryKey,
   2300                                isLocaleAware = mCursor->IsLocaleAware(),
   2301                                keyCompareOperator = GetKeyOperator(mDirection),
   2302                                transactionSerialNumber =
   2303                                    mTransaction->LoggingSerialNumber(),
   2304                                requestSerialNumber =
   2305                                    GetRequest()->LoggingSerialNumber()](
   2306                                   const auto& currentCachedResponse) {
   2307          // This duplicates the logic from the parent. We could avoid this
   2308          // duplication if we invalidated the cached records always for any
   2309          // continue-with-key operation, but would lose the benefits of
   2310          // preloading then.
   2311          const auto& cachedSortKey =
   2312              currentCachedResponse.GetSortKey(isLocaleAware);
   2313          const auto& cachedSortPrimaryKey =
   2314              currentCachedResponse.mObjectStoreKey;
   2315 
   2316          const bool discard =
   2317              (cachedSortKey == key &&
   2318               !(cachedSortPrimaryKey.*keyCompareOperator)(primaryKey)) ||
   2319              !(cachedSortKey.*keyCompareOperator)(key);
   2320 
   2321          if (discard) {
   2322            IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2323                "PRELOAD: Continue to key %s with primary key %s, discarding "
   2324                "cached key %s with cached primary key %s",
   2325                "Continue, discarding%.0s%.0s%.0s%.0s", transactionSerialNumber,
   2326                requestSerialNumber, key.GetBuffer().get(),
   2327                primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
   2328                cachedSortPrimaryKey.GetBuffer().get());
   2329          } else {
   2330            IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2331                "PRELOAD: Continue to key %s with primary key %s, keeping "
   2332                "cached key %s with cached primary key %s and further",
   2333                "Continue, keeping%.0s%.0s%.0s%.0s", transactionSerialNumber,
   2334                requestSerialNumber, key.GetBuffer().get(),
   2335                primaryKey.GetBuffer().get(), cachedSortKey.GetBuffer().get(),
   2336                cachedSortPrimaryKey.GetBuffer().get());
   2337          }
   2338 
   2339          return discard;
   2340        });
   2341      } else {
   2342        MOZ_CRASH("Shouldn't get here");
   2343      }
   2344 
   2345      break;
   2346    }
   2347 
   2348    case CursorRequestParams::TAdvanceParams: {
   2349      uint32_t& advanceCount = params.get_AdvanceParams().count();
   2350      IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2351          "PRELOAD: Advancing %" PRIu32 " records", "Advancing %" PRIu32,
   2352          mTransaction->LoggingSerialNumber(),
   2353          GetRequest()->LoggingSerialNumber(), advanceCount);
   2354 
   2355      // Discard cache entries.
   2356      DiscardCachedResponses([&advanceCount, &currentKey,
   2357                              &currentObjectStoreKey](
   2358                                 const auto& currentCachedResponse) {
   2359        const bool res = advanceCount > 1;
   2360        if (res) {
   2361          --advanceCount;
   2362 
   2363          // TODO: We only need to update currentKey on the last entry, the
   2364          // others are overwritten in the next iteration anyway.
   2365          currentKey = currentCachedResponse.mKey;
   2366          if constexpr (!CursorTypeTraits<CursorType>::IsObjectStoreCursor) {
   2367            currentObjectStoreKey = currentCachedResponse.mObjectStoreKey;
   2368          } else {
   2369            (void)currentObjectStoreKey;
   2370          }
   2371        }
   2372        return res;
   2373      });
   2374      break;
   2375    }
   2376 
   2377    default:
   2378      MOZ_CRASH("Should never get here!");
   2379  }
   2380 
   2381  if (!mCachedResponses.empty()) {
   2382    // We need to remove the response here from mCachedResponses, since when
   2383    // requests are interleaved, other events may be processed before
   2384    // CompleteContinueRequestFromCache, which may modify mCachedResponses.
   2385    mDelayedResponses.emplace_back(std::move(mCachedResponses.front()));
   2386    mCachedResponses.pop_front();
   2387 
   2388    // We cannot send the response right away, as we must preserve the request
   2389    // order. Dispatching a DelayedActionRunnable only partially addresses this.
   2390    // This is accompanied by invalidating cached entries at proper locations to
   2391    // make it correct. To avoid this, further changes are necessary, see Bug
   2392    // 1580499.
   2393    MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(
   2394        MakeAndAddRef<DelayedActionRunnable<BackgroundCursorChild<CursorType>>>(
   2395            SafeRefPtrFromThis(),
   2396            &BackgroundCursorChild::CompleteContinueRequestFromCache)));
   2397 
   2398    // TODO: Could we preload further entries in the background when the size of
   2399    // mCachedResponses falls under some threshold? Or does the response
   2400    // handling model disallow this?
   2401  } else {
   2402    MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendContinue(
   2403        aRequestId, params, currentKey, currentObjectStoreKey));
   2404  }
   2405 }
   2406 
   2407 template <IDBCursorType CursorType>
   2408 void BackgroundCursorChild<CursorType>::CompleteContinueRequestFromCache() {
   2409  AssertIsOnOwningThread();
   2410  MOZ_ASSERT(mTransaction);
   2411  MOZ_ASSERT(mCursor);
   2412  MOZ_ASSERT(mStrongCursor);
   2413  MOZ_ASSERT(!mDelayedResponses.empty());
   2414  MOZ_ASSERT(mCursor->GetType() == CursorType);
   2415 
   2416  const RefPtr<IDBCursor> cursor = std::move(mStrongCursor);
   2417 
   2418  mCursor->Reset(std::move(mDelayedResponses.front()));
   2419  mDelayedResponses.pop_front();
   2420 
   2421  IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2422      "PRELOAD: Consumed 1 cached response, %zu cached responses remaining",
   2423      "Consumed cached response, %zu remaining",
   2424      mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
   2425      mDelayedResponses.size() + mCachedResponses.size());
   2426 
   2427  SetResultAndDispatchSuccessEvent(
   2428      GetRequest(),
   2429      mTransaction
   2430          ? SafeRefPtr{&mTransaction.ref(), AcquireStrongRefFromRawPtr{}}
   2431          : nullptr,
   2432      *cursor);
   2433 
   2434  mTransaction->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
   2435 }
   2436 
   2437 template <IDBCursorType CursorType>
   2438 void BackgroundCursorChild<CursorType>::SendDeleteMeInternal() {
   2439  AssertIsOnOwningThread();
   2440  MOZ_ASSERT(!mStrongRequest);
   2441  MOZ_ASSERT(!mStrongCursor);
   2442 
   2443  mRequest.destroy();
   2444  mTransaction = Nothing();
   2445  // TODO: The things until here could be pulled up to
   2446  // BackgroundCursorChildBase.
   2447 
   2448  mSource.destroy();
   2449 
   2450  if (mCursor) {
   2451    mCursor->ClearBackgroundActor();
   2452    mCursor = nullptr;
   2453 
   2454    MOZ_ALWAYS_TRUE(PBackgroundIDBCursorChild::SendDeleteMe());
   2455  }
   2456 }
   2457 
   2458 template <IDBCursorType CursorType>
   2459 void BackgroundCursorChild<CursorType>::InvalidateCachedResponses() {
   2460  AssertIsOnOwningThread();
   2461  MOZ_ASSERT(mTransaction);
   2462  MOZ_ASSERT(mRequest);
   2463 
   2464  // TODO: With more information on the reason for the invalidation, we might
   2465  // only selectively invalidate cached responses. If the reason is an updated
   2466  // value, we do not need to care for key-only cursors. If the key of the
   2467  // changed entry is not in the remaining range of the cursor, we also do not
   2468  // need to care, etc.
   2469 
   2470  IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2471      "PRELOAD: Invalidating all %zu cached responses", "Invalidating %zu",
   2472      mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
   2473      mCachedResponses.size());
   2474 
   2475  mCachedResponses.clear();
   2476 
   2477  // We only hold a strong cursor reference in mStrongCursor when
   2478  // continue()/similar has been called. In those cases we expect a response
   2479  // that will be received in the future, and it may include prefetched data
   2480  // that needs to be discarded.
   2481  if (mStrongCursor) {
   2482    IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2483        "PRELOAD: Setting flag to invalidate in-flight responses",
   2484        "Set flag to invalidate in-flight responses",
   2485        mTransaction->LoggingSerialNumber(),
   2486        GetRequest()->LoggingSerialNumber());
   2487 
   2488    mInFlightResponseInvalidationNeeded = true;
   2489  }
   2490 }
   2491 
   2492 template <IDBCursorType CursorType>
   2493 template <typename Condition>
   2494 void BackgroundCursorChild<CursorType>::DiscardCachedResponses(
   2495    const Condition& aConditionFunc) {
   2496  size_t discardedCount = 0;
   2497  while (!mCachedResponses.empty() &&
   2498         aConditionFunc(mCachedResponses.front())) {
   2499    mCachedResponses.pop_front();
   2500    ++discardedCount;
   2501  }
   2502  IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2503      "PRELOAD: Discarded %zu cached responses, %zu remaining",
   2504      "Discarded %zu; remaining %zu", mTransaction->LoggingSerialNumber(),
   2505      GetRequest()->LoggingSerialNumber(), discardedCount,
   2506      mCachedResponses.size());
   2507 }
   2508 
   2509 BackgroundCursorChildBase::~BackgroundCursorChildBase() = default;
   2510 
   2511 void BackgroundCursorChildBase::HandleResponse(nsresult aResponse) {
   2512  AssertIsOnOwningThread();
   2513  MOZ_ASSERT(NS_FAILED(aResponse));
   2514  MOZ_ASSERT(NS_ERROR_GET_MODULE(aResponse) == NS_ERROR_MODULE_DOM_INDEXEDDB);
   2515  MOZ_ASSERT(mRequest);
   2516  MOZ_ASSERT(mTransaction);
   2517  MOZ_ASSERT(!mStrongRequest);
   2518  MOZ_ASSERT(!mStrongCursor);
   2519 
   2520  DispatchErrorEvent(
   2521      GetRequest(), aResponse,
   2522      SafeRefPtr{&mTransaction.ref(), AcquireStrongRefFromRawPtr{}});
   2523 }
   2524 
   2525 template <IDBCursorType CursorType>
   2526 void BackgroundCursorChild<CursorType>::HandleResponse(
   2527    const void_t& aResponse) {
   2528  AssertIsOnOwningThread();
   2529  MOZ_ASSERT(mRequest);
   2530  MOZ_ASSERT(mTransaction);
   2531  MOZ_ASSERT(!mStrongRequest);
   2532  MOZ_ASSERT(!mStrongCursor);
   2533 
   2534  if (mCursor) {
   2535    mCursor->Reset();
   2536  }
   2537 
   2538  SetResultAndDispatchSuccessEvent(
   2539      GetRequest(),
   2540      mTransaction
   2541          ? SafeRefPtr{&mTransaction.ref(), AcquireStrongRefFromRawPtr{}}
   2542          : nullptr,
   2543      JS::NullHandleValue);
   2544 
   2545  if (!mCursor) {
   2546    MOZ_ALWAYS_SUCCEEDS(this->GetActorEventTarget()->Dispatch(
   2547        MakeAndAddRef<DelayedActionRunnable<BackgroundCursorChild<CursorType>>>(
   2548            SafeRefPtrFromThis(), &BackgroundCursorChild::SendDeleteMeInternal),
   2549        NS_DISPATCH_NORMAL));
   2550  }
   2551 }
   2552 
   2553 template <IDBCursorType CursorType>
   2554 template <typename... Args>
   2555 RefPtr<IDBCursor>
   2556 BackgroundCursorChild<CursorType>::HandleIndividualCursorResponse(
   2557    const bool aUseAsCurrentResult, Args&&... aArgs) {
   2558  if (mCursor) {
   2559    if (aUseAsCurrentResult) {
   2560      mCursor->Reset(CursorData<CursorType>{std::forward<Args>(aArgs)...});
   2561    } else {
   2562      mCachedResponses.emplace_back(std::forward<Args>(aArgs)...);
   2563    }
   2564    return nullptr;
   2565  }
   2566 
   2567  MOZ_ASSERT(aUseAsCurrentResult);
   2568 
   2569  // TODO: This still looks quite dangerous to me. Why is mCursor not a
   2570  // RefPtr?
   2571  auto newCursor = IDBCursor::Create(this, std::forward<Args>(aArgs)...);
   2572  mCursor = newCursor;
   2573  return newCursor;
   2574 }
   2575 
   2576 template <IDBCursorType CursorType>
   2577 template <typename Func>
   2578 void BackgroundCursorChild<CursorType>::HandleMultipleCursorResponses(
   2579    nsTArray<ResponseType>&& aResponses, const Func& aHandleRecord) {
   2580  AssertIsOnOwningThread();
   2581  MOZ_ASSERT(mRequest);
   2582  MOZ_ASSERT(mTransaction);
   2583  MOZ_ASSERT(!mStrongRequest);
   2584  MOZ_ASSERT(!mStrongCursor);
   2585  MOZ_ASSERT(aResponses.Length() > 0);
   2586 
   2587  IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2588      "PRELOAD: Received %zu cursor responses", "Received %zu",
   2589      mTransaction->LoggingSerialNumber(), GetRequest()->LoggingSerialNumber(),
   2590      aResponses.Length());
   2591  MOZ_ASSERT_IF(aResponses.Length() > 1, mCachedResponses.empty());
   2592 
   2593  // If a new cursor is created, we need to keep a reference to it until the
   2594  // SetResultAndDispatchSuccessEvent creates a DOM Binding.
   2595  RefPtr<IDBCursor> strongNewCursor;
   2596 
   2597  bool isFirst = true;
   2598  for (auto& response : aResponses) {
   2599    IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2600        "PRELOAD: Processing response for key %s", "Processing%.0s",
   2601        mTransaction->LoggingSerialNumber(),
   2602        GetRequest()->LoggingSerialNumber(), response.key().GetBuffer().get());
   2603 
   2604    // TODO: At the moment, we only send a cursor request to the parent if
   2605    // requested by the user code. Therefore, the first result is always used
   2606    // as the current result, and the potential extra results are cached. If
   2607    // we extended this towards preloading in the background, all results
   2608    // might need to be cached.
   2609    auto maybeNewCursor =
   2610        aHandleRecord(/* aUseAsCurrentResult */ isFirst, std::move(response));
   2611    if (maybeNewCursor) {
   2612      MOZ_ASSERT(!strongNewCursor);
   2613      strongNewCursor = std::move(maybeNewCursor);
   2614    }
   2615    isFirst = false;
   2616 
   2617    if (mInFlightResponseInvalidationNeeded) {
   2618      IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
   2619          "PRELOAD: Discarding remaining responses since "
   2620          "mInFlightResponseInvalidationNeeded is set",
   2621          "Discarding responses", mTransaction->LoggingSerialNumber(),
   2622          GetRequest()->LoggingSerialNumber());
   2623 
   2624      mInFlightResponseInvalidationNeeded = false;
   2625      break;
   2626    }
   2627  }
   2628 
   2629  SetResultAndDispatchSuccessEvent(
   2630      GetRequest(),
   2631      mTransaction
   2632          ? SafeRefPtr{&mTransaction.ref(), AcquireStrongRefFromRawPtr{}}
   2633          : nullptr,
   2634      *static_cast<IDBCursor*>(mCursor));
   2635 }
   2636 
   2637 template <IDBCursorType CursorType>
   2638 void BackgroundCursorChild<CursorType>::HandleResponse(
   2639    nsTArray<ResponseType>&& aResponses) {
   2640  AssertIsOnOwningThread();
   2641 
   2642  if constexpr (CursorType == IDBCursorType::ObjectStore ||
   2643                CursorType == IDBCursorType::Index) {
   2644    MOZ_ASSERT(mTransaction);
   2645 
   2646    if (!mTransaction->Database()->GetOwnerGlobal()) {
   2647      // Ignore the response, since we have already been disconnected from the
   2648      // global.
   2649      return;
   2650    }
   2651  }
   2652 
   2653  if constexpr (CursorType == IDBCursorType::ObjectStore) {
   2654    HandleMultipleCursorResponses(
   2655        std::move(aResponses), [this](const bool useAsCurrentResult,
   2656                                      ObjectStoreCursorResponse&& response) {
   2657          // TODO: Maybe move the deserialization of the clone-read-info into
   2658          // the cursor, so that it is only done for records actually accessed,
   2659          // which might not be the case for all cached records.
   2660          return HandleIndividualCursorResponse(
   2661              useAsCurrentResult, std::move(response.key()),
   2662              DeserializeStructuredCloneReadInfo(
   2663                  std::move(response.cloneInfo()), mTransaction->Database(),
   2664                  PreprocessingNotSupported));
   2665        });
   2666  }
   2667  if constexpr (CursorType == IDBCursorType::ObjectStoreKey) {
   2668    HandleMultipleCursorResponses(
   2669        std::move(aResponses), [this](const bool useAsCurrentResult,
   2670                                      ObjectStoreKeyCursorResponse&& response) {
   2671          return HandleIndividualCursorResponse(useAsCurrentResult,
   2672                                                std::move(response.key()));
   2673        });
   2674  }
   2675  if constexpr (CursorType == IDBCursorType::Index) {
   2676    HandleMultipleCursorResponses(
   2677        std::move(aResponses),
   2678        [this](const bool useAsCurrentResult, IndexCursorResponse&& response) {
   2679          return HandleIndividualCursorResponse(
   2680              useAsCurrentResult, std::move(response.key()),
   2681              std::move(response.sortKey()), std::move(response.objectKey()),
   2682              DeserializeStructuredCloneReadInfo(
   2683                  std::move(response.cloneInfo()), mTransaction->Database(),
   2684                  PreprocessingNotSupported));
   2685        });
   2686  }
   2687  if constexpr (CursorType == IDBCursorType::IndexKey) {
   2688    HandleMultipleCursorResponses(
   2689        std::move(aResponses), [this](const bool useAsCurrentResult,
   2690                                      IndexKeyCursorResponse&& response) {
   2691          return HandleIndividualCursorResponse(
   2692              useAsCurrentResult, std::move(response.key()),
   2693              std::move(response.sortKey()), std::move(response.objectKey()));
   2694        });
   2695  }
   2696 }
   2697 
   2698 template <IDBCursorType CursorType>
   2699 void BackgroundCursorChild<CursorType>::ActorDestroy(ActorDestroyReason aWhy) {
   2700  AssertIsOnOwningThread();
   2701  MOZ_ASSERT_IF(aWhy == Deletion, !mStrongRequest);
   2702  MOZ_ASSERT_IF(aWhy == Deletion, !mStrongCursor);
   2703 
   2704  MaybeCollectGarbageOnIPCMessage();
   2705 
   2706  if (mStrongRequest && !mStrongCursor && mTransaction) {
   2707    mTransaction->OnRequestFinished(/* aRequestCompletedSuccessfully */
   2708                                    aWhy == Deletion);
   2709  }
   2710 
   2711  if (mCursor) {
   2712    mCursor->ClearBackgroundActor();
   2713 #ifdef DEBUG
   2714    mCursor = nullptr;
   2715 #endif
   2716  }
   2717 
   2718 #ifdef DEBUG
   2719  mRequest.maybeDestroy();
   2720  mTransaction = Nothing();
   2721  mSource.maybeDestroy();
   2722 #endif
   2723 }
   2724 
   2725 template <IDBCursorType CursorType>
   2726 mozilla::ipc::IPCResult BackgroundCursorChild<CursorType>::RecvResponse(
   2727    CursorResponse&& aResponse) {
   2728  AssertIsOnOwningThread();
   2729  MOZ_ASSERT(aResponse.type() != CursorResponse::T__None);
   2730  MOZ_ASSERT(mRequest);
   2731  MOZ_ASSERT(mTransaction);
   2732  MOZ_ASSERT_IF(mCursor, mStrongCursor);
   2733  MOZ_ASSERT_IF(!mCursor, mStrongRequest);
   2734 
   2735  MaybeCollectGarbageOnIPCMessage();
   2736 
   2737  const RefPtr<IDBRequest> request = std::move(mStrongRequest);
   2738  (void)request;  // XXX see Bug 1605075
   2739  const RefPtr<IDBCursor> cursor = std::move(mStrongCursor);
   2740  (void)cursor;  // XXX see Bug 1605075
   2741 
   2742  const auto transaction =
   2743      SafeRefPtr{&mTransaction.ref(), AcquireStrongRefFromRawPtr{}};
   2744 
   2745  switch (aResponse.type()) {
   2746    case CursorResponse::Tnsresult:
   2747      HandleResponse(aResponse.get_nsresult());
   2748      break;
   2749 
   2750    case CursorResponse::Tvoid_t:
   2751      HandleResponse(aResponse.get_void_t());
   2752      break;
   2753 
   2754    case CursorResponse::TArrayOfObjectStoreCursorResponse:
   2755      if constexpr (CursorType == IDBCursorType::ObjectStore) {
   2756        HandleResponse(
   2757            std::move(aResponse.get_ArrayOfObjectStoreCursorResponse()));
   2758      } else {
   2759        MOZ_CRASH("Response type mismatch");
   2760      }
   2761      break;
   2762 
   2763    case CursorResponse::TArrayOfObjectStoreKeyCursorResponse:
   2764      if constexpr (CursorType == IDBCursorType::ObjectStoreKey) {
   2765        HandleResponse(
   2766            std::move(aResponse.get_ArrayOfObjectStoreKeyCursorResponse()));
   2767      } else {
   2768        MOZ_CRASH("Response type mismatch");
   2769      }
   2770      break;
   2771 
   2772    case CursorResponse::TArrayOfIndexCursorResponse:
   2773      if constexpr (CursorType == IDBCursorType::Index) {
   2774        HandleResponse(std::move(aResponse.get_ArrayOfIndexCursorResponse()));
   2775      } else {
   2776        MOZ_CRASH("Response type mismatch");
   2777      }
   2778      break;
   2779 
   2780    case CursorResponse::TArrayOfIndexKeyCursorResponse:
   2781      if constexpr (CursorType == IDBCursorType::IndexKey) {
   2782        HandleResponse(
   2783            std::move(aResponse.get_ArrayOfIndexKeyCursorResponse()));
   2784      } else {
   2785        MOZ_CRASH("Response type mismatch");
   2786      }
   2787      break;
   2788 
   2789    default:
   2790      MOZ_CRASH("Should never get here!");
   2791  }
   2792 
   2793  transaction->OnRequestFinished(/* aRequestCompletedSuccessfully */ true);
   2794 
   2795  return IPC_OK();
   2796 }
   2797 
   2798 template class BackgroundCursorChild<IDBCursorType::ObjectStore>;
   2799 template class BackgroundCursorChild<IDBCursorType::ObjectStoreKey>;
   2800 template class BackgroundCursorChild<IDBCursorType::Index>;
   2801 template class BackgroundCursorChild<IDBCursorType::IndexKey>;
   2802 
   2803 template <typename T>
   2804 NS_IMETHODIMP DelayedActionRunnable<T>::Run() {
   2805  MOZ_ASSERT(mActor);
   2806  mActor->AssertIsOnOwningThread();
   2807  MOZ_ASSERT(mRequest);
   2808  MOZ_ASSERT(mActionFunc);
   2809 
   2810  ((*mActor).*mActionFunc)();
   2811 
   2812  mActor = nullptr;
   2813  mRequest = nullptr;
   2814 
   2815  return NS_OK;
   2816 }
   2817 
   2818 template <typename T>
   2819 nsresult DelayedActionRunnable<T>::Cancel() {
   2820  if (NS_WARN_IF(!mActor)) {
   2821    return NS_ERROR_UNEXPECTED;
   2822  }
   2823 
   2824  // This must always run to clean up our state.
   2825  Run();
   2826 
   2827  return NS_OK;
   2828 }
   2829 
   2830 /*******************************************************************************
   2831 * BackgroundUtilsChild
   2832 ******************************************************************************/
   2833 
   2834 BackgroundUtilsChild::BackgroundUtilsChild(IndexedDatabaseManager* aManager)
   2835    : mManager(aManager) {
   2836  AssertIsOnOwningThread();
   2837  MOZ_ASSERT(aManager);
   2838 
   2839  MOZ_COUNT_CTOR(indexedDB::BackgroundUtilsChild);
   2840 }
   2841 
   2842 BackgroundUtilsChild::~BackgroundUtilsChild() {
   2843  MOZ_COUNT_DTOR(indexedDB::BackgroundUtilsChild);
   2844 }
   2845 
   2846 void BackgroundUtilsChild::SendDeleteMeInternal() {
   2847  AssertIsOnOwningThread();
   2848 
   2849  if (mManager) {
   2850    mManager->ClearBackgroundActor();
   2851    mManager = nullptr;
   2852 
   2853    MOZ_ALWAYS_TRUE(PBackgroundIndexedDBUtilsChild::SendDeleteMe());
   2854  }
   2855 }
   2856 
   2857 void BackgroundUtilsChild::ActorDestroy(ActorDestroyReason aWhy) {
   2858  AssertIsOnOwningThread();
   2859 
   2860  if (mManager) {
   2861    mManager->ClearBackgroundActor();
   2862 #ifdef DEBUG
   2863    mManager = nullptr;
   2864 #endif
   2865  }
   2866 }
   2867 
   2868 }  // namespace dom::indexedDB
   2869 }  // namespace mozilla