Bug 1472338: part 2) Change `clipboard.readText()` to read from the clipboard asynchr...
[gecko.git] / dom / indexedDB / IDBIndex.cpp
blob95b27973494d9df11ac9396dfe42a91090668055
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 "IDBIndex.h"
9 #include "IDBCursorType.h"
10 #include "IDBDatabase.h"
11 #include "IDBEvents.h"
12 #include "IDBKeyRange.h"
13 #include "IDBObjectStore.h"
14 #include "IDBRequest.h"
15 #include "IDBTransaction.h"
16 #include "IndexedDatabase.h"
17 #include "IndexedDatabaseInlines.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
20 #include "ProfilerHelpers.h"
21 #include "ReportInternalError.h"
23 // Include this last to avoid path problems on Windows.
24 #include "ActorsChild.h"
26 namespace mozilla::dom {
28 using namespace mozilla::dom::indexedDB;
30 namespace {
32 MovingNotNull<RefPtr<IDBRequest>> GenerateRequest(JSContext* aCx,
33 IDBIndex* aIndex) {
34 MOZ_ASSERT(aIndex);
35 aIndex->AssertIsOnOwningThread();
37 auto transaction = aIndex->ObjectStore()->AcquireTransaction();
38 auto* const database = transaction->Database();
40 return IDBRequest::Create(aCx, aIndex, database, std::move(transaction));
43 } // namespace
45 IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata)
46 : mObjectStore(aObjectStore),
47 mCachedKeyPath(JS::UndefinedValue()),
48 mMetadata(aMetadata),
49 mId(aMetadata->id()),
50 mRooted(false) {
51 MOZ_ASSERT(aObjectStore);
52 aObjectStore->AssertIsOnOwningThread();
53 MOZ_ASSERT(aMetadata);
56 IDBIndex::~IDBIndex() {
57 AssertIsOnOwningThread();
59 if (mRooted) {
60 mozilla::DropJSObjects(this);
64 RefPtr<IDBIndex> IDBIndex::Create(IDBObjectStore* aObjectStore,
65 const IndexMetadata& aMetadata) {
66 MOZ_ASSERT(aObjectStore);
67 aObjectStore->AssertIsOnOwningThread();
69 return new IDBIndex(aObjectStore, &aMetadata);
72 #ifdef DEBUG
74 void IDBIndex::AssertIsOnOwningThread() const {
75 MOZ_ASSERT(mObjectStore);
76 mObjectStore->AssertIsOnOwningThread();
79 #endif // DEBUG
81 RefPtr<IDBRequest> IDBIndex::OpenCursor(JSContext* aCx,
82 JS::Handle<JS::Value> aRange,
83 IDBCursorDirection aDirection,
84 ErrorResult& aRv) {
85 AssertIsOnOwningThread();
87 return OpenCursorInternal(/* aKeysOnly */ false, aCx, aRange, aDirection,
88 aRv);
91 RefPtr<IDBRequest> IDBIndex::OpenKeyCursor(JSContext* aCx,
92 JS::Handle<JS::Value> aRange,
93 IDBCursorDirection aDirection,
94 ErrorResult& aRv) {
95 AssertIsOnOwningThread();
97 return OpenCursorInternal(/* aKeysOnly */ true, aCx, aRange, aDirection, aRv);
100 RefPtr<IDBRequest> IDBIndex::Get(JSContext* aCx, JS::Handle<JS::Value> aKey,
101 ErrorResult& aRv) {
102 AssertIsOnOwningThread();
104 return GetInternal(/* aKeyOnly */ false, aCx, aKey, aRv);
107 RefPtr<IDBRequest> IDBIndex::GetKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
108 ErrorResult& aRv) {
109 AssertIsOnOwningThread();
111 return GetInternal(/* aKeyOnly */ true, aCx, aKey, aRv);
114 RefPtr<IDBRequest> IDBIndex::GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey,
115 const Optional<uint32_t>& aLimit,
116 ErrorResult& aRv) {
117 AssertIsOnOwningThread();
119 return GetAllInternal(/* aKeysOnly */ false, aCx, aKey, aLimit, aRv);
122 RefPtr<IDBRequest> IDBIndex::GetAllKeys(JSContext* aCx,
123 JS::Handle<JS::Value> aKey,
124 const Optional<uint32_t>& aLimit,
125 ErrorResult& aRv) {
126 AssertIsOnOwningThread();
128 return GetAllInternal(/* aKeysOnly */ true, aCx, aKey, aLimit, aRv);
131 void IDBIndex::RefreshMetadata(bool aMayDelete) {
132 AssertIsOnOwningThread();
133 MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata.get());
135 const auto& indexes = mObjectStore->Spec().indexes();
136 const auto foundIt = std::find_if(
137 indexes.cbegin(), indexes.cend(),
138 [id = Id()](const auto& metadata) { return metadata.id() == id; });
139 const bool found = foundIt != indexes.cend();
141 MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found);
143 if (found) {
144 mMetadata = &*foundIt;
145 MOZ_ASSERT(mMetadata != mDeletedMetadata.get());
146 mDeletedMetadata = nullptr;
147 } else {
148 NoteDeletion();
152 void IDBIndex::NoteDeletion() {
153 AssertIsOnOwningThread();
154 MOZ_ASSERT(mMetadata);
155 MOZ_ASSERT(Id() == mMetadata->id());
157 if (mDeletedMetadata) {
158 MOZ_ASSERT(mMetadata == mDeletedMetadata.get());
159 return;
162 mDeletedMetadata = MakeUnique<IndexMetadata>(*mMetadata);
164 mMetadata = mDeletedMetadata.get();
167 const nsString& IDBIndex::Name() const {
168 AssertIsOnOwningThread();
169 MOZ_ASSERT(mMetadata);
171 return mMetadata->name();
174 void IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv) {
175 AssertIsOnOwningThread();
177 const auto& transaction = mObjectStore->TransactionRef();
179 if (transaction.GetMode() != IDBTransaction::Mode::VersionChange ||
180 mDeletedMetadata) {
181 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
182 return;
185 if (!transaction.IsActive()) {
186 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
187 return;
190 if (aName == mMetadata->name()) {
191 return;
194 // Cache logging string of this index before renaming.
195 const LoggingString loggingOldIndex(this);
197 const int64_t indexId = Id();
199 nsresult rv =
200 transaction.Database()->RenameIndex(mObjectStore->Id(), indexId, aName);
202 if (NS_FAILED(rv)) {
203 aRv.Throw(rv);
204 return;
207 // Don't do this in the macro because we always need to increment the serial
208 // number to keep in sync with the parent.
209 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
211 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
212 "database(%s).transaction(%s).objectStore(%s).index(%s)."
213 "rename(%s)",
214 "IDBIndex.rename(%.0s%.0s%.0s%.0s%.0s)",
215 transaction.LoggingSerialNumber(), requestSerialNumber,
216 IDB_LOG_STRINGIFY(transaction.Database()), IDB_LOG_STRINGIFY(transaction),
217 IDB_LOG_STRINGIFY(mObjectStore), loggingOldIndex.get(),
218 IDB_LOG_STRINGIFY(this));
220 mObjectStore->MutableTransactionRef().RenameIndex(mObjectStore, indexId,
221 aName);
224 bool IDBIndex::Unique() const {
225 AssertIsOnOwningThread();
226 MOZ_ASSERT(mMetadata);
228 return mMetadata->unique();
231 bool IDBIndex::MultiEntry() const {
232 AssertIsOnOwningThread();
233 MOZ_ASSERT(mMetadata);
235 return mMetadata->multiEntry();
238 bool IDBIndex::LocaleAware() const {
239 AssertIsOnOwningThread();
240 MOZ_ASSERT(mMetadata);
242 return mMetadata->locale().IsEmpty();
245 const indexedDB::KeyPath& IDBIndex::GetKeyPath() const {
246 AssertIsOnOwningThread();
247 MOZ_ASSERT(mMetadata);
249 return mMetadata->keyPath();
252 void IDBIndex::GetLocale(nsString& aLocale) const {
253 AssertIsOnOwningThread();
254 MOZ_ASSERT(mMetadata);
256 if (mMetadata->locale().IsEmpty()) {
257 SetDOMStringToNull(aLocale);
258 } else {
259 CopyASCIItoUTF16(mMetadata->locale(), aLocale);
263 const nsCString& IDBIndex::Locale() const {
264 AssertIsOnOwningThread();
265 MOZ_ASSERT(mMetadata);
267 return mMetadata->locale();
270 bool IDBIndex::IsAutoLocale() const {
271 AssertIsOnOwningThread();
272 MOZ_ASSERT(mMetadata);
274 return mMetadata->autoLocale();
277 nsIGlobalObject* IDBIndex::GetParentObject() const {
278 AssertIsOnOwningThread();
280 return mObjectStore->GetParentObject();
283 void IDBIndex::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
284 ErrorResult& aRv) {
285 AssertIsOnOwningThread();
287 if (!mCachedKeyPath.isUndefined()) {
288 MOZ_ASSERT(mRooted);
289 aResult.set(mCachedKeyPath);
290 return;
293 MOZ_ASSERT(!mRooted);
295 aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
296 if (NS_WARN_IF(aRv.Failed())) {
297 return;
300 if (mCachedKeyPath.isGCThing()) {
301 mozilla::HoldJSObjects(this);
302 mRooted = true;
305 aResult.set(mCachedKeyPath);
308 RefPtr<IDBRequest> IDBIndex::GetInternal(bool aKeyOnly, JSContext* aCx,
309 JS::Handle<JS::Value> aKey,
310 ErrorResult& aRv) {
311 AssertIsOnOwningThread();
313 if (mDeletedMetadata) {
314 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
315 return nullptr;
318 const auto& transaction = mObjectStore->TransactionRef();
319 if (!transaction.IsActive()) {
320 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
321 return nullptr;
324 RefPtr<IDBKeyRange> keyRange;
325 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv);
326 if (NS_WARN_IF(aRv.Failed())) {
327 return nullptr;
330 if (!keyRange) {
331 // Must specify a key or keyRange for get() and getKey().
332 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_KEY_ERR);
333 return nullptr;
336 const int64_t objectStoreId = mObjectStore->Id();
337 const int64_t indexId = Id();
339 SerializedKeyRange serializedKeyRange;
340 keyRange->ToSerialized(serializedKeyRange);
342 RequestParams params;
344 if (aKeyOnly) {
345 params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange);
346 } else {
347 params = IndexGetParams(objectStoreId, indexId, serializedKeyRange);
350 auto request = GenerateRequest(aCx, this).unwrap();
352 if (aKeyOnly) {
353 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
354 "database(%s).transaction(%s).objectStore(%s).index(%s)."
355 "getKey(%s)",
356 "IDBIndex.getKey(%.0s%.0s%.0s%.0s%.0s)",
357 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(),
358 IDB_LOG_STRINGIFY(transaction.Database()),
359 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
360 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange));
361 } else {
362 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
363 "database(%s).transaction(%s).objectStore(%s).index(%s)."
364 "get(%s)",
365 "IDBIndex.get(%.0s%.0s%.0s%.0s%.0s)", transaction.LoggingSerialNumber(),
366 request->LoggingSerialNumber(),
367 IDB_LOG_STRINGIFY(transaction.Database()),
368 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
369 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange));
372 auto& mutableTransaction = mObjectStore->MutableTransactionRef();
374 // TODO: This is necessary to preserve request ordering only. Proper
375 // sequencing of requests should be done in a more sophisticated manner that
376 // doesn't require invalidating cursor caches (Bug 1580499).
377 mutableTransaction.InvalidateCursorCaches();
379 mutableTransaction.StartRequest(request, params);
381 return request;
384 RefPtr<IDBRequest> IDBIndex::GetAllInternal(bool aKeysOnly, JSContext* aCx,
385 JS::Handle<JS::Value> aKey,
386 const Optional<uint32_t>& aLimit,
387 ErrorResult& aRv) {
388 AssertIsOnOwningThread();
390 if (mDeletedMetadata) {
391 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
392 return nullptr;
395 const auto& transaction = mObjectStore->TransactionRef();
396 if (!transaction.IsActive()) {
397 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
398 return nullptr;
401 RefPtr<IDBKeyRange> keyRange;
402 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv);
403 if (NS_WARN_IF(aRv.Failed())) {
404 return nullptr;
407 const int64_t objectStoreId = mObjectStore->Id();
408 const int64_t indexId = Id();
410 Maybe<SerializedKeyRange> optionalKeyRange;
411 if (keyRange) {
412 SerializedKeyRange serializedKeyRange;
413 keyRange->ToSerialized(serializedKeyRange);
414 optionalKeyRange.emplace(serializedKeyRange);
417 const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
419 const auto& params =
420 aKeysOnly ? RequestParams{IndexGetAllKeysParams(objectStoreId, indexId,
421 optionalKeyRange, limit)}
422 : RequestParams{IndexGetAllParams(objectStoreId, indexId,
423 optionalKeyRange, limit)};
425 auto request = GenerateRequest(aCx, this).unwrap();
427 if (aKeysOnly) {
428 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
429 "database(%s).transaction(%s).objectStore(%s).index(%s)."
430 "getAllKeys(%s, %s)",
431 "IDBIndex.getAllKeys(%.0s%.0s%.0s%.0s%.0s%.0s)",
432 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(),
433 IDB_LOG_STRINGIFY(transaction.Database()),
434 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
435 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
436 IDB_LOG_STRINGIFY(aLimit));
437 } else {
438 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
439 "database(%s).transaction(%s).objectStore(%s).index(%s)."
440 "getAll(%s, %s)",
441 "IDBIndex.getAll(%.0s%.0s%.0s%.0s%.0s%.0s)",
442 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(),
443 IDB_LOG_STRINGIFY(transaction.Database()),
444 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
445 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
446 IDB_LOG_STRINGIFY(aLimit));
449 auto& mutableTransaction = mObjectStore->MutableTransactionRef();
451 // TODO: This is necessary to preserve request ordering only. Proper
452 // sequencing of requests should be done in a more sophisticated manner that
453 // doesn't require invalidating cursor caches (Bug 1580499).
454 mutableTransaction.InvalidateCursorCaches();
456 mutableTransaction.StartRequest(request, params);
458 return request;
461 RefPtr<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx,
462 JS::Handle<JS::Value> aRange,
463 IDBCursorDirection aDirection,
464 ErrorResult& aRv) {
465 AssertIsOnOwningThread();
467 if (mDeletedMetadata) {
468 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
469 return nullptr;
472 const auto& transaction = mObjectStore->TransactionRef();
473 if (!transaction.IsActive()) {
474 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
475 return nullptr;
478 RefPtr<IDBKeyRange> keyRange;
479 IDBKeyRange::FromJSVal(aCx, aRange, &keyRange, aRv);
480 if (NS_WARN_IF(aRv.Failed())) {
481 return nullptr;
484 const int64_t objectStoreId = mObjectStore->Id();
485 const int64_t indexId = Id();
487 Maybe<SerializedKeyRange> optionalKeyRange;
489 if (keyRange) {
490 SerializedKeyRange serializedKeyRange;
491 keyRange->ToSerialized(serializedKeyRange);
493 optionalKeyRange.emplace(std::move(serializedKeyRange));
496 const CommonIndexOpenCursorParams commonIndexParams = {
497 {objectStoreId, std::move(optionalKeyRange), aDirection}, indexId};
499 const auto params =
500 aKeysOnly ? OpenCursorParams{IndexOpenKeyCursorParams{commonIndexParams}}
501 : OpenCursorParams{IndexOpenCursorParams{commonIndexParams}};
503 auto request = GenerateRequest(aCx, this).unwrap();
505 if (aKeysOnly) {
506 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
507 "database(%s).transaction(%s).objectStore(%s).index(%s)."
508 "openKeyCursor(%s, %s)",
509 "IDBIndex.openKeyCursor(%.0s%.0s%.0s%.0s%.0s%.0s)",
510 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(),
511 IDB_LOG_STRINGIFY(transaction.Database()),
512 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
513 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
514 IDB_LOG_STRINGIFY(aDirection));
515 } else {
516 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
517 "database(%s).transaction(%s).objectStore(%s).index(%s)."
518 "openCursor(%s, %s)",
519 "IDBIndex.openCursor(%.0s%.0s%.0s%.0s%.0s%.0s)",
520 transaction.LoggingSerialNumber(), request->LoggingSerialNumber(),
521 IDB_LOG_STRINGIFY(transaction.Database()),
522 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
523 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange),
524 IDB_LOG_STRINGIFY(aDirection));
527 const auto actor =
528 aKeysOnly
529 ? static_cast<SafeRefPtr<BackgroundCursorChildBase>>(
530 MakeSafeRefPtr<BackgroundCursorChild<IDBCursorType::IndexKey>>(
531 request, this, aDirection))
532 : MakeSafeRefPtr<BackgroundCursorChild<IDBCursorType::Index>>(
533 request, this, aDirection);
535 auto& mutableTransaction = mObjectStore->MutableTransactionRef();
537 // TODO: This is necessary to preserve request ordering only. Proper
538 // sequencing of requests should be done in a more sophisticated manner that
539 // doesn't require invalidating cursor caches (Bug 1580499).
540 mutableTransaction.InvalidateCursorCaches();
542 mutableTransaction.OpenCursor(*actor, params);
544 return request;
547 RefPtr<IDBRequest> IDBIndex::Count(JSContext* aCx, JS::Handle<JS::Value> aKey,
548 ErrorResult& aRv) {
549 AssertIsOnOwningThread();
551 if (mDeletedMetadata) {
552 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
553 return nullptr;
556 const auto& transaction = mObjectStore->TransactionRef();
557 if (!transaction.IsActive()) {
558 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
559 return nullptr;
562 RefPtr<IDBKeyRange> keyRange;
563 IDBKeyRange::FromJSVal(aCx, aKey, &keyRange, aRv);
564 if (aRv.Failed()) {
565 return nullptr;
568 IndexCountParams params;
569 params.objectStoreId() = mObjectStore->Id();
570 params.indexId() = Id();
572 if (keyRange) {
573 SerializedKeyRange serializedKeyRange;
574 keyRange->ToSerialized(serializedKeyRange);
575 params.optionalKeyRange().emplace(serializedKeyRange);
578 auto request = GenerateRequest(aCx, this).unwrap();
580 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
581 "database(%s).transaction(%s).objectStore(%s).index(%s)."
582 "count(%s)",
583 "IDBIndex.count(%.0s%.0s%.0s%.0s%.0s)", transaction.LoggingSerialNumber(),
584 request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction.Database()),
585 IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore),
586 IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange));
588 auto& mutableTransaction = mObjectStore->MutableTransactionRef();
590 // TODO: This is necessary to preserve request ordering only. Proper
591 // sequencing of requests should be done in a more sophisticated manner that
592 // doesn't require invalidating cursor caches (Bug 1580499).
593 mutableTransaction.InvalidateCursorCaches();
595 mutableTransaction.StartRequest(request, params);
597 return request;
600 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex)
601 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex)
603 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex)
604 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
605 NS_INTERFACE_MAP_ENTRY(nsISupports)
606 NS_INTERFACE_MAP_END
608 NS_IMPL_CYCLE_COLLECTION_MULTI_ZONE_JSHOLDER_CLASS(IDBIndex)
610 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex)
611 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
612 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
613 NS_IMPL_CYCLE_COLLECTION_TRACE_END
615 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
616 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
617 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
619 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex)
620 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
622 // Don't unlink mObjectStore!
624 tmp->mCachedKeyPath.setUndefined();
626 if (tmp->mRooted) {
627 mozilla::DropJSObjects(tmp);
628 tmp->mRooted = false;
630 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
632 JSObject* IDBIndex::WrapObject(JSContext* aCx,
633 JS::Handle<JSObject*> aGivenProto) {
634 return IDBIndex_Binding::Wrap(aCx, this, aGivenProto);
637 } // namespace mozilla::dom