Backed out changeset a673a5760795 (bug 1894131) for causing V-swr and SM bustages...
[gecko.git] / dom / indexedDB / IDBRequest.cpp
blobefc3f9a44e01ca0b5ad0f3fab94b410fea6a5e9c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "IDBRequest.h"
9 #include <utility>
11 #include "BackgroundChildImpl.h"
12 #include "IDBCursor.h"
13 #include "IDBDatabase.h"
14 #include "IDBEvents.h"
15 #include "IDBFactory.h"
16 #include "IDBIndex.h"
17 #include "IDBObjectStore.h"
18 #include "IDBTransaction.h"
19 #include "IndexedDatabaseManager.h"
20 #include "ReportInternalError.h"
21 #include "mozilla/ContentEvents.h"
22 #include "mozilla/ErrorResult.h"
23 #include "mozilla/EventDispatcher.h"
24 #include "mozilla/HoldDropJSObjects.h"
25 #include "mozilla/dom/DOMException.h"
26 #include "mozilla/dom/ErrorEventBinding.h"
27 #include "mozilla/dom/IDBOpenDBRequestBinding.h"
28 #include "mozilla/dom/ScriptSettings.h"
29 #include "mozilla/dom/WorkerPrivate.h"
30 #include "mozilla/dom/WorkerRef.h"
31 #include "nsCOMPtr.h"
32 #include "nsContentUtils.h"
33 #include "nsIGlobalObject.h"
34 #include "nsIScriptContext.h"
35 #include "nsJSUtils.h"
36 #include "nsString.h"
37 #include "ThreadLocal.h"
39 namespace mozilla::dom {
41 using namespace mozilla::dom::indexedDB;
42 using namespace mozilla::ipc;
44 IDBRequest::IDBRequest(IDBDatabase* aDatabase)
45 : DOMEventTargetHelper(aDatabase),
46 mLoggingSerialNumber(0),
47 mLineNo(0),
48 mColumn(0),
49 mHaveResultOrErrorCode(false) {
50 MOZ_ASSERT(aDatabase);
51 aDatabase->AssertIsOnOwningThread();
53 InitMembers();
56 IDBRequest::IDBRequest(nsIGlobalObject* aGlobal)
57 : DOMEventTargetHelper(aGlobal),
58 mLoggingSerialNumber(0),
59 mLineNo(0),
60 mColumn(0),
61 mHaveResultOrErrorCode(false) {
62 InitMembers();
65 IDBRequest::~IDBRequest() {
66 AssertIsOnOwningThread();
67 mozilla::DropJSObjects(this);
70 void IDBRequest::InitMembers() {
71 AssertIsOnOwningThread();
73 mResultVal.setUndefined();
74 mLoggingSerialNumber = NextSerialNumber();
75 mErrorCode = NS_OK;
76 mLineNo = 0;
77 mColumn = 0;
78 mHaveResultOrErrorCode = false;
81 // static
82 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
83 JSContext* aCx, IDBDatabase* aDatabase,
84 SafeRefPtr<IDBTransaction> aTransaction) {
85 MOZ_ASSERT(aCx);
86 MOZ_ASSERT(aDatabase);
87 aDatabase->AssertIsOnOwningThread();
89 RefPtr<IDBRequest> request = new IDBRequest(aDatabase);
90 CaptureCaller(aCx, request->mFilename, &request->mLineNo, &request->mColumn);
92 request->mTransaction = std::move(aTransaction);
94 return WrapMovingNotNullUnchecked(std::move(request));
97 // static
98 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
99 JSContext* aCx, IDBObjectStore* aSourceAsObjectStore,
100 IDBDatabase* aDatabase, SafeRefPtr<IDBTransaction> aTransaction) {
101 MOZ_ASSERT(aSourceAsObjectStore);
102 aSourceAsObjectStore->AssertIsOnOwningThread();
104 auto request =
105 Create(aCx, aDatabase, std::move(aTransaction)).unwrapBasePtr();
107 request->mSourceAsObjectStore = aSourceAsObjectStore;
109 return WrapMovingNotNullUnchecked(std::move(request));
112 // static
113 MovingNotNull<RefPtr<IDBRequest>> IDBRequest::Create(
114 JSContext* aCx, IDBIndex* aSourceAsIndex, IDBDatabase* aDatabase,
115 SafeRefPtr<IDBTransaction> aTransaction) {
116 MOZ_ASSERT(aSourceAsIndex);
117 aSourceAsIndex->AssertIsOnOwningThread();
119 auto request =
120 Create(aCx, aDatabase, std::move(aTransaction)).unwrapBasePtr();
122 request->mSourceAsIndex = aSourceAsIndex;
124 return WrapMovingNotNullUnchecked(std::move(request));
127 // static
128 uint64_t IDBRequest::NextSerialNumber() {
129 BackgroundChildImpl::ThreadLocal* threadLocal =
130 BackgroundChildImpl::GetThreadLocalForCurrentThread();
131 MOZ_ASSERT(threadLocal);
133 const auto& idbThreadLocal = threadLocal->mIndexedDBThreadLocal;
134 MOZ_ASSERT(idbThreadLocal);
136 return idbThreadLocal->NextRequestSN();
139 void IDBRequest::SetLoggingSerialNumber(uint64_t aLoggingSerialNumber) {
140 AssertIsOnOwningThread();
141 MOZ_ASSERT(aLoggingSerialNumber > mLoggingSerialNumber);
143 mLoggingSerialNumber = aLoggingSerialNumber;
146 void IDBRequest::CaptureCaller(JSContext* aCx, nsAString& aFilename,
147 uint32_t* aLineNo, uint32_t* aColumn) {
148 MOZ_ASSERT(aFilename.IsEmpty());
149 MOZ_ASSERT(aLineNo);
150 MOZ_ASSERT(aColumn);
152 nsJSUtils::GetCallingLocation(aCx, aFilename, aLineNo, aColumn);
155 void IDBRequest::GetSource(
156 Nullable<OwningIDBObjectStoreOrIDBIndexOrIDBCursor>& aSource) const {
157 AssertIsOnOwningThread();
159 MOZ_ASSERT_IF(mSourceAsObjectStore, !mSourceAsIndex);
160 MOZ_ASSERT_IF(mSourceAsIndex, !mSourceAsObjectStore);
161 MOZ_ASSERT_IF(mSourceAsCursor, mSourceAsObjectStore || mSourceAsIndex);
163 // Always check cursor first since cursor requests hold both the cursor and
164 // the objectStore or index the cursor came from.
165 if (mSourceAsCursor) {
166 aSource.SetValue().SetAsIDBCursor() = mSourceAsCursor;
167 } else if (mSourceAsObjectStore) {
168 aSource.SetValue().SetAsIDBObjectStore() = mSourceAsObjectStore;
169 } else if (mSourceAsIndex) {
170 aSource.SetValue().SetAsIDBIndex() = mSourceAsIndex;
171 } else {
172 aSource.SetNull();
176 void IDBRequest::Reset() {
177 AssertIsOnOwningThread();
179 mResultVal.setUndefined();
181 mHaveResultOrErrorCode = false;
182 mError = nullptr;
185 void IDBRequest::SetError(nsresult aRv) {
186 AssertIsOnOwningThread();
187 MOZ_ASSERT(NS_FAILED(aRv));
188 MOZ_ASSERT(NS_ERROR_GET_MODULE(aRv) == NS_ERROR_MODULE_DOM_INDEXEDDB);
189 MOZ_ASSERT(!mError);
191 mHaveResultOrErrorCode = true;
192 mError = DOMException::Create(aRv);
193 mErrorCode = aRv;
195 mResultVal.setUndefined();
198 #ifdef DEBUG
200 nsresult IDBRequest::GetErrorCode() const {
201 AssertIsOnOwningThread();
202 MOZ_ASSERT(mHaveResultOrErrorCode);
204 return mErrorCode;
207 DOMException* IDBRequest::GetErrorAfterResult() const {
208 AssertIsOnOwningThread();
209 MOZ_ASSERT(mHaveResultOrErrorCode);
211 return mError;
214 #endif // DEBUG
216 void IDBRequest::GetCallerLocation(nsAString& aFilename, uint32_t* aLineNo,
217 uint32_t* aColumn) const {
218 AssertIsOnOwningThread();
219 MOZ_ASSERT(aLineNo);
220 MOZ_ASSERT(aColumn);
222 aFilename = mFilename;
223 *aLineNo = mLineNo;
224 *aColumn = mColumn;
227 IDBRequestReadyState IDBRequest::ReadyState() const {
228 AssertIsOnOwningThread();
230 return IsPending() ? IDBRequestReadyState::Pending
231 : IDBRequestReadyState::Done;
234 void IDBRequest::SetSource(IDBCursor* aSource) {
235 AssertIsOnOwningThread();
236 MOZ_ASSERT(aSource);
237 MOZ_ASSERT(mSourceAsObjectStore || mSourceAsIndex);
238 MOZ_ASSERT(!mSourceAsCursor);
240 mSourceAsCursor = aSource;
243 JSObject* IDBRequest::WrapObject(JSContext* aCx,
244 JS::Handle<JSObject*> aGivenProto) {
245 return IDBRequest_Binding::Wrap(aCx, this, aGivenProto);
248 void IDBRequest::GetResult(JS::MutableHandle<JS::Value> aResult,
249 ErrorResult& aRv) const {
250 AssertIsOnOwningThread();
252 if (!mHaveResultOrErrorCode) {
253 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
254 return;
257 aResult.set(mResultVal);
260 DOMException* IDBRequest::GetError(ErrorResult& aRv) {
261 AssertIsOnOwningThread();
263 if (!mHaveResultOrErrorCode) {
264 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
265 return nullptr;
268 return mError;
271 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBRequest)
273 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
274 DOMEventTargetHelper)
275 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsObjectStore)
276 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsIndex)
277 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceAsCursor)
278 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
279 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mError)
280 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
282 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
283 DOMEventTargetHelper)
284 mozilla::DropJSObjects(tmp);
285 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsObjectStore)
286 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsIndex)
287 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceAsCursor)
288 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction)
289 NS_IMPL_CYCLE_COLLECTION_UNLINK(mError)
290 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
292 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IDBRequest, DOMEventTargetHelper)
293 // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
294 // DOMEventTargetHelper does it for us.
295 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultVal)
296 NS_IMPL_CYCLE_COLLECTION_TRACE_END
298 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBRequest)
299 if (aIID.Equals(NS_GET_IID(mozilla::dom::detail::PrivateIDBRequest))) {
300 foundInterface = static_cast<EventTarget*>(this);
301 } else
302 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
304 NS_IMPL_ADDREF_INHERITED(IDBRequest, DOMEventTargetHelper)
305 NS_IMPL_RELEASE_INHERITED(IDBRequest, DOMEventTargetHelper)
307 void IDBRequest::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
308 AssertIsOnOwningThread();
310 aVisitor.mCanHandle = true;
311 aVisitor.SetParentTarget(mTransaction.unsafeGetRawPtr(), false);
314 IDBOpenDBRequest::IDBOpenDBRequest(SafeRefPtr<IDBFactory> aFactory,
315 nsIGlobalObject* aGlobal)
316 : IDBRequest(aGlobal),
317 mFactory(std::move(aFactory)),
318 mIncreasedActiveDatabaseCount(false) {
319 AssertIsOnOwningThread();
320 MOZ_ASSERT(mFactory);
321 MOZ_ASSERT(aGlobal);
324 IDBOpenDBRequest::~IDBOpenDBRequest() {
325 AssertIsOnOwningThread();
326 MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
329 // static
330 RefPtr<IDBOpenDBRequest> IDBOpenDBRequest::Create(
331 JSContext* aCx, SafeRefPtr<IDBFactory> aFactory, nsIGlobalObject* aGlobal) {
332 MOZ_ASSERT(aFactory);
333 aFactory->AssertIsOnOwningThread();
334 MOZ_ASSERT(aGlobal);
336 RefPtr<IDBOpenDBRequest> request =
337 new IDBOpenDBRequest(std::move(aFactory), aGlobal);
338 CaptureCaller(aCx, request->mFilename, &request->mLineNo, &request->mColumn);
340 if (!NS_IsMainThread()) {
341 WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
342 MOZ_ASSERT(workerPrivate);
344 workerPrivate->AssertIsOnWorkerThread();
346 request->mWorkerRef =
347 StrongWorkerRef::Create(workerPrivate, "IDBOpenDBRequest");
348 if (NS_WARN_IF(!request->mWorkerRef)) {
349 return nullptr;
353 request->IncreaseActiveDatabaseCount();
355 return request;
358 void IDBOpenDBRequest::SetTransaction(SafeRefPtr<IDBTransaction> aTransaction) {
359 AssertIsOnOwningThread();
361 MOZ_ASSERT(!aTransaction || !mTransaction);
363 mTransaction = std::move(aTransaction);
366 void IDBOpenDBRequest::DispatchNonTransactionError(nsresult aErrorCode) {
367 AssertIsOnOwningThread();
368 MOZ_ASSERT(NS_FAILED(aErrorCode));
369 MOZ_ASSERT(NS_ERROR_GET_MODULE(aErrorCode) == NS_ERROR_MODULE_DOM_INDEXEDDB);
371 // The actor failed to initiate, decrease the number of active IDBOpenRequests
372 // here since NoteComplete won't be called.
373 MaybeDecreaseActiveDatabaseCount();
375 SetError(aErrorCode);
377 // Make an error event and fire it at the target.
378 auto event = CreateGenericEvent(this, nsDependentString(kErrorEventType),
379 eDoesBubble, eCancelable);
381 IgnoredErrorResult rv;
382 DispatchEvent(*event, rv);
383 if (rv.Failed()) {
384 NS_WARNING("Failed to dispatch event!");
388 void IDBOpenDBRequest::NoteComplete() {
389 AssertIsOnOwningThread();
390 MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerRef);
392 // Normally, we decrease the number of active IDBOpenRequests here.
393 MaybeDecreaseActiveDatabaseCount();
395 // If we have a WorkerRef, then nulling this out will release the worker.
396 mWorkerRef = nullptr;
399 void IDBOpenDBRequest::IncreaseActiveDatabaseCount() {
400 AssertIsOnOwningThread();
401 MOZ_ASSERT(!mIncreasedActiveDatabaseCount);
403 // Increase the number of active IDBOpenRequests.
404 // Note: We count here instead of the actor's ctor because the preemption
405 // could happen at next JS interrupt but its BackgroundFactoryRequestChild
406 // could be created asynchronously from IDBFactory::BackgroundCreateCallback
407 // ::ActorCreated() if its PBackgroundChild is not created yet on this thread.
408 mFactory->UpdateActiveDatabaseCount(1);
409 mIncreasedActiveDatabaseCount = true;
412 void IDBOpenDBRequest::MaybeDecreaseActiveDatabaseCount() {
413 AssertIsOnOwningThread();
415 if (mIncreasedActiveDatabaseCount) {
416 // Decrease the number of active IDBOpenRequests.
417 mFactory->UpdateActiveDatabaseCount(-1);
418 mIncreasedActiveDatabaseCount = false;
422 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
424 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest)
425 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
426 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
428 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest, IDBRequest)
429 // Don't unlink mFactory!
430 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
432 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBOpenDBRequest)
433 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
435 NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
436 NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
438 JSObject* IDBOpenDBRequest::WrapObject(JSContext* aCx,
439 JS::Handle<JSObject*> aGivenProto) {
440 AssertIsOnOwningThread();
442 return IDBOpenDBRequest_Binding::Wrap(aCx, this, aGivenProto);
445 } // namespace mozilla::dom