1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "IDBIndex.h"
8
9 #include "FileInfo.h"
10 #include "IDBCursor.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"
22
23 // Include this last to avoid path problems on Windows.
24 #include "ActorsChild.h"
25
26 namespace mozilla {
27 namespace dom {
28
29 namespace {
30
31 already_AddRefed<IDBRequest>
GenerateRequest(JSContext * aCx,IDBIndex * aIndex)32 GenerateRequest(JSContext* aCx, IDBIndex* aIndex)
33 {
34 MOZ_ASSERT(aIndex);
35 aIndex->AssertIsOnOwningThread();
36
37 IDBTransaction* transaction = aIndex->ObjectStore()->Transaction();
38
39 RefPtr<IDBRequest> request =
40 IDBRequest::Create(aCx, aIndex, transaction->Database(), transaction);
41 MOZ_ASSERT(request);
42
43 return request.forget();
44 }
45
46 } // namespace
47
IDBIndex(IDBObjectStore * aObjectStore,const IndexMetadata * aMetadata)48 IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata)
49 : mObjectStore(aObjectStore)
50 , mCachedKeyPath(JS::UndefinedValue())
51 , mMetadata(aMetadata)
52 , mId(aMetadata->id())
53 , mRooted(false)
54 {
55 MOZ_ASSERT(aObjectStore);
56 aObjectStore->AssertIsOnOwningThread();
57 MOZ_ASSERT(aMetadata);
58 }
59
~IDBIndex()60 IDBIndex::~IDBIndex()
61 {
62 AssertIsOnOwningThread();
63
64 if (mRooted) {
65 mCachedKeyPath.setUndefined();
66 mozilla::DropJSObjects(this);
67 }
68 }
69
70 already_AddRefed<IDBIndex>
Create(IDBObjectStore * aObjectStore,const IndexMetadata & aMetadata)71 IDBIndex::Create(IDBObjectStore* aObjectStore,
72 const IndexMetadata& aMetadata)
73 {
74 MOZ_ASSERT(aObjectStore);
75 aObjectStore->AssertIsOnOwningThread();
76
77 RefPtr<IDBIndex> index = new IDBIndex(aObjectStore, &aMetadata);
78
79 return index.forget();
80 }
81
82 #ifdef DEBUG
83
84 void
AssertIsOnOwningThread() const85 IDBIndex::AssertIsOnOwningThread() const
86 {
87 MOZ_ASSERT(mObjectStore);
88 mObjectStore->AssertIsOnOwningThread();
89 }
90
91 #endif // DEBUG
92
93 void
RefreshMetadata(bool aMayDelete)94 IDBIndex::RefreshMetadata(bool aMayDelete)
95 {
96 AssertIsOnOwningThread();
97 MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata);
98
99 const nsTArray<IndexMetadata>& indexes = mObjectStore->Spec().indexes();
100
101 bool found = false;
102
103 for (uint32_t count = indexes.Length(), index = 0;
104 index < count;
105 index++) {
106 const IndexMetadata& metadata = indexes[index];
107
108 if (metadata.id() == Id()) {
109 mMetadata = &metadata;
110
111 found = true;
112 break;
113 }
114 }
115
116 MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found);
117
118 if (found) {
119 MOZ_ASSERT(mMetadata != mDeletedMetadata);
120 mDeletedMetadata = nullptr;
121 } else {
122 NoteDeletion();
123 }
124 }
125
126 void
NoteDeletion()127 IDBIndex::NoteDeletion()
128 {
129 AssertIsOnOwningThread();
130 MOZ_ASSERT(mMetadata);
131 MOZ_ASSERT(Id() == mMetadata->id());
132
133 if (mDeletedMetadata) {
134 MOZ_ASSERT(mMetadata == mDeletedMetadata);
135 return;
136 }
137
138 mDeletedMetadata = new IndexMetadata(*mMetadata);
139
140 mMetadata = mDeletedMetadata;
141 }
142
143 const nsString&
Name() const144 IDBIndex::Name() const
145 {
146 AssertIsOnOwningThread();
147 MOZ_ASSERT(mMetadata);
148
149 return mMetadata->name();
150 }
151
152 void
SetName(const nsAString & aName,ErrorResult & aRv)153 IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv)
154 {
155 AssertIsOnOwningThread();
156
157 IDBTransaction* transaction = mObjectStore->Transaction();
158
159 if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE ||
160 mDeletedMetadata) {
161 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
162 return;
163 }
164
165 if (!transaction->IsOpen()) {
166 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
167 return;
168 }
169
170 if (aName == mMetadata->name()) {
171 return;
172 }
173
174 // Cache logging string of this index before renaming.
175 const LoggingString loggingOldIndex(this);
176
177 const int64_t indexId = Id();
178
179 nsresult rv =
180 transaction->Database()->RenameIndex(mObjectStore->Id(),
181 indexId,
182 aName);
183
184 if (NS_FAILED(rv)) {
185 aRv.Throw(rv);
186 return;
187 }
188
189 // Don't do this in the macro because we always need to increment the serial
190 // number to keep in sync with the parent.
191 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
192
193 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
194 "database(%s).transaction(%s).objectStore(%s).index(%s)."
195 "rename(%s)",
196 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()",
197 IDB_LOG_ID_STRING(),
198 transaction->LoggingSerialNumber(),
199 requestSerialNumber,
200 IDB_LOG_STRINGIFY(transaction->Database()),
201 IDB_LOG_STRINGIFY(transaction),
202 IDB_LOG_STRINGIFY(mObjectStore),
203 loggingOldIndex.get(),
204 IDB_LOG_STRINGIFY(this));
205
206 transaction->RenameIndex(mObjectStore, indexId, aName);
207 }
208
209 bool
Unique() const210 IDBIndex::Unique() const
211 {
212 AssertIsOnOwningThread();
213 MOZ_ASSERT(mMetadata);
214
215 return mMetadata->unique();
216 }
217
218 bool
MultiEntry() const219 IDBIndex::MultiEntry() const
220 {
221 AssertIsOnOwningThread();
222 MOZ_ASSERT(mMetadata);
223
224 return mMetadata->multiEntry();
225 }
226
227 bool
LocaleAware() const228 IDBIndex::LocaleAware() const
229 {
230 AssertIsOnOwningThread();
231 MOZ_ASSERT(mMetadata);
232
233 return mMetadata->locale().IsEmpty();
234 }
235
236 const indexedDB::KeyPath&
GetKeyPath() const237 IDBIndex::GetKeyPath() const
238 {
239 AssertIsOnOwningThread();
240 MOZ_ASSERT(mMetadata);
241
242 return mMetadata->keyPath();
243 }
244
245 void
GetLocale(nsString & aLocale) const246 IDBIndex::GetLocale(nsString& aLocale) const
247 {
248 AssertIsOnOwningThread();
249 MOZ_ASSERT(mMetadata);
250
251 if (mMetadata->locale().IsEmpty()) {
252 SetDOMStringToNull(aLocale);
253 } else {
254 aLocale.AssignWithConversion(mMetadata->locale());
255 }
256 }
257
258 const nsCString&
Locale() const259 IDBIndex::Locale() const
260 {
261 AssertIsOnOwningThread();
262 MOZ_ASSERT(mMetadata);
263
264 return mMetadata->locale();
265 }
266
267 bool
IsAutoLocale() const268 IDBIndex::IsAutoLocale() const
269 {
270 AssertIsOnOwningThread();
271 MOZ_ASSERT(mMetadata);
272
273 return mMetadata->autoLocale();
274 }
275
276 nsPIDOMWindowInner*
GetParentObject() const277 IDBIndex::GetParentObject() const
278 {
279 AssertIsOnOwningThread();
280
281 return mObjectStore->GetParentObject();
282 }
283
284 void
GetKeyPath(JSContext * aCx,JS::MutableHandle<JS::Value> aResult,ErrorResult & aRv)285 IDBIndex::GetKeyPath(JSContext* aCx,
286 JS::MutableHandle<JS::Value> aResult,
287 ErrorResult& aRv)
288 {
289 AssertIsOnOwningThread();
290
291 if (!mCachedKeyPath.isUndefined()) {
292 MOZ_ASSERT(mRooted);
293 aResult.set(mCachedKeyPath);
294 return;
295 }
296
297 MOZ_ASSERT(!mRooted);
298
299 aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
300 if (NS_WARN_IF(aRv.Failed())) {
301 return;
302 }
303
304 if (mCachedKeyPath.isGCThing()) {
305 mozilla::HoldJSObjects(this);
306 mRooted = true;
307 }
308
309 aResult.set(mCachedKeyPath);
310 }
311
312 already_AddRefed<IDBRequest>
GetInternal(bool aKeyOnly,JSContext * aCx,JS::Handle<JS::Value> aKey,ErrorResult & aRv)313 IDBIndex::GetInternal(bool aKeyOnly,
314 JSContext* aCx,
315 JS::Handle<JS::Value> aKey,
316 ErrorResult& aRv)
317 {
318 AssertIsOnOwningThread();
319
320 if (mDeletedMetadata) {
321 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
322 return nullptr;
323 }
324
325 IDBTransaction* transaction = mObjectStore->Transaction();
326 if (!transaction->IsOpen()) {
327 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
328 return nullptr;
329 }
330
331 RefPtr<IDBKeyRange> keyRange;
332 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
333 if (NS_WARN_IF(aRv.Failed())) {
334 return nullptr;
335 }
336
337 if (!keyRange) {
338 // Must specify a key or keyRange for get() and getKey().
339 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
340 return nullptr;
341 }
342
343 const int64_t objectStoreId = mObjectStore->Id();
344 const int64_t indexId = Id();
345
346 SerializedKeyRange serializedKeyRange;
347 keyRange->ToSerialized(serializedKeyRange);
348
349 RequestParams params;
350
351 if (aKeyOnly) {
352 params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange);
353 } else {
354 params = IndexGetParams(objectStoreId, indexId, serializedKeyRange);
355 }
356
357 RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
358 MOZ_ASSERT(request);
359
360 if (aKeyOnly) {
361 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
362 "database(%s).transaction(%s).objectStore(%s).index(%s)."
363 "getKey(%s)",
364 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()",
365 IDB_LOG_ID_STRING(),
366 transaction->LoggingSerialNumber(),
367 request->LoggingSerialNumber(),
368 IDB_LOG_STRINGIFY(transaction->Database()),
369 IDB_LOG_STRINGIFY(transaction),
370 IDB_LOG_STRINGIFY(mObjectStore),
371 IDB_LOG_STRINGIFY(this),
372 IDB_LOG_STRINGIFY(keyRange));
373 } else {
374 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
375 "database(%s).transaction(%s).objectStore(%s).index(%s)."
376 "get(%s)",
377 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()",
378 IDB_LOG_ID_STRING(),
379 transaction->LoggingSerialNumber(),
380 request->LoggingSerialNumber(),
381 IDB_LOG_STRINGIFY(transaction->Database()),
382 IDB_LOG_STRINGIFY(transaction),
383 IDB_LOG_STRINGIFY(mObjectStore),
384 IDB_LOG_STRINGIFY(this),
385 IDB_LOG_STRINGIFY(keyRange));
386 }
387
388 transaction->StartRequest(request, params);
389
390 return request.forget();
391 }
392
393 already_AddRefed<IDBRequest>
GetAllInternal(bool aKeysOnly,JSContext * aCx,JS::Handle<JS::Value> aKey,const Optional<uint32_t> & aLimit,ErrorResult & aRv)394 IDBIndex::GetAllInternal(bool aKeysOnly,
395 JSContext* aCx,
396 JS::Handle<JS::Value> aKey,
397 const Optional<uint32_t>& aLimit,
398 ErrorResult& aRv)
399 {
400 AssertIsOnOwningThread();
401
402 if (mDeletedMetadata) {
403 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
404 return nullptr;
405 }
406
407 IDBTransaction* transaction = mObjectStore->Transaction();
408 if (!transaction->IsOpen()) {
409 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
410 return nullptr;
411 }
412
413 RefPtr<IDBKeyRange> keyRange;
414 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
415 if (NS_WARN_IF(aRv.Failed())) {
416 return nullptr;
417 }
418
419 const int64_t objectStoreId = mObjectStore->Id();
420 const int64_t indexId = Id();
421
422 OptionalKeyRange optionalKeyRange;
423 if (keyRange) {
424 SerializedKeyRange serializedKeyRange;
425 keyRange->ToSerialized(serializedKeyRange);
426 optionalKeyRange = serializedKeyRange;
427 } else {
428 optionalKeyRange = void_t();
429 }
430
431 const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0;
432
433 RequestParams params;
434 if (aKeysOnly) {
435 params = IndexGetAllKeysParams(objectStoreId, indexId, optionalKeyRange,
436 limit);
437 } else {
438 params = IndexGetAllParams(objectStoreId, indexId, optionalKeyRange, limit);
439 }
440
441 RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
442 MOZ_ASSERT(request);
443
444 if (aKeysOnly) {
445 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
446 "database(%s).transaction(%s).objectStore(%s).index(%s)."
447 "getAllKeys(%s, %s)",
448 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()",
449 IDB_LOG_ID_STRING(),
450 transaction->LoggingSerialNumber(),
451 request->LoggingSerialNumber(),
452 IDB_LOG_STRINGIFY(transaction->Database()),
453 IDB_LOG_STRINGIFY(transaction),
454 IDB_LOG_STRINGIFY(mObjectStore),
455 IDB_LOG_STRINGIFY(this),
456 IDB_LOG_STRINGIFY(keyRange),
457 IDB_LOG_STRINGIFY(aLimit));
458 } else {
459 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
460 "database(%s).transaction(%s).objectStore(%s).index(%s)."
461 "getAll(%s, %s)",
462 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()",
463 IDB_LOG_ID_STRING(),
464 transaction->LoggingSerialNumber(),
465 request->LoggingSerialNumber(),
466 IDB_LOG_STRINGIFY(transaction->Database()),
467 IDB_LOG_STRINGIFY(transaction),
468 IDB_LOG_STRINGIFY(mObjectStore),
469 IDB_LOG_STRINGIFY(this),
470 IDB_LOG_STRINGIFY(keyRange),
471 IDB_LOG_STRINGIFY(aLimit));
472 }
473
474 transaction->StartRequest(request, params);
475
476 return request.forget();
477 }
478
479 already_AddRefed<IDBRequest>
OpenCursorInternal(bool aKeysOnly,JSContext * aCx,JS::Handle<JS::Value> aRange,IDBCursorDirection aDirection,ErrorResult & aRv)480 IDBIndex::OpenCursorInternal(bool aKeysOnly,
481 JSContext* aCx,
482 JS::Handle<JS::Value> aRange,
483 IDBCursorDirection aDirection,
484 ErrorResult& aRv)
485 {
486 AssertIsOnOwningThread();
487
488 if (mDeletedMetadata) {
489 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
490 return nullptr;
491 }
492
493 IDBTransaction* transaction = mObjectStore->Transaction();
494 if (!transaction->IsOpen()) {
495 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
496 return nullptr;
497 }
498
499 RefPtr<IDBKeyRange> keyRange;
500 aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
501 if (NS_WARN_IF(aRv.Failed())) {
502 return nullptr;
503 }
504
505 int64_t objectStoreId = mObjectStore->Id();
506 int64_t indexId = Id();
507
508 OptionalKeyRange optionalKeyRange;
509
510 if (keyRange) {
511 SerializedKeyRange serializedKeyRange;
512 keyRange->ToSerialized(serializedKeyRange);
513
514 optionalKeyRange = Move(serializedKeyRange);
515 } else {
516 optionalKeyRange = void_t();
517 }
518
519 IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
520
521 OpenCursorParams params;
522 if (aKeysOnly) {
523 IndexOpenKeyCursorParams openParams;
524 openParams.objectStoreId() = objectStoreId;
525 openParams.indexId() = indexId;
526 openParams.optionalKeyRange() = Move(optionalKeyRange);
527 openParams.direction() = direction;
528
529 params = Move(openParams);
530 } else {
531 IndexOpenCursorParams openParams;
532 openParams.objectStoreId() = objectStoreId;
533 openParams.indexId() = indexId;
534 openParams.optionalKeyRange() = Move(optionalKeyRange);
535 openParams.direction() = direction;
536
537 params = Move(openParams);
538 }
539
540 RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
541 MOZ_ASSERT(request);
542
543 if (aKeysOnly) {
544 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
545 "database(%s).transaction(%s).objectStore(%s).index(%s)."
546 "openKeyCursor(%s, %s)",
547 "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()",
548 IDB_LOG_ID_STRING(),
549 transaction->LoggingSerialNumber(),
550 request->LoggingSerialNumber(),
551 IDB_LOG_STRINGIFY(transaction->Database()),
552 IDB_LOG_STRINGIFY(transaction),
553 IDB_LOG_STRINGIFY(mObjectStore),
554 IDB_LOG_STRINGIFY(this),
555 IDB_LOG_STRINGIFY(keyRange),
556 IDB_LOG_STRINGIFY(direction));
557 } else {
558 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
559 "database(%s).transaction(%s).objectStore(%s).index(%s)."
560 "openCursor(%s, %s)",
561 "IndexedDB %s: C T[%lld] R[%llu]: "
562 "IDBObjectStore.openKeyCursor()",
563 IDB_LOG_ID_STRING(),
564 transaction->LoggingSerialNumber(),
565 request->LoggingSerialNumber(),
566 IDB_LOG_STRINGIFY(transaction->Database()),
567 IDB_LOG_STRINGIFY(transaction),
568 IDB_LOG_STRINGIFY(mObjectStore),
569 IDB_LOG_STRINGIFY(this),
570 IDB_LOG_STRINGIFY(keyRange),
571 IDB_LOG_STRINGIFY(direction));
572 }
573
574 BackgroundCursorChild* actor =
575 new BackgroundCursorChild(request, this, direction);
576
577 mObjectStore->Transaction()->OpenCursor(actor, params);
578
579 return request.forget();
580 }
581
582 already_AddRefed<IDBRequest>
Count(JSContext * aCx,JS::Handle<JS::Value> aKey,ErrorResult & aRv)583 IDBIndex::Count(JSContext* aCx,
584 JS::Handle<JS::Value> aKey,
585 ErrorResult& aRv)
586 {
587 AssertIsOnOwningThread();
588
589 if (mDeletedMetadata) {
590 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
591 return nullptr;
592 }
593
594 IDBTransaction* transaction = mObjectStore->Transaction();
595 if (!transaction->IsOpen()) {
596 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
597 return nullptr;
598 }
599
600 RefPtr<IDBKeyRange> keyRange;
601 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
602 if (aRv.Failed()) {
603 return nullptr;
604 }
605
606 IndexCountParams params;
607 params.objectStoreId() = mObjectStore->Id();
608 params.indexId() = Id();
609
610 if (keyRange) {
611 SerializedKeyRange serializedKeyRange;
612 keyRange->ToSerialized(serializedKeyRange);
613 params.optionalKeyRange() = serializedKeyRange;
614 } else {
615 params.optionalKeyRange() = void_t();
616 }
617
618 RefPtr<IDBRequest> request = GenerateRequest(aCx, this);
619 MOZ_ASSERT(request);
620
621 IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: "
622 "database(%s).transaction(%s).objectStore(%s).index(%s)."
623 "count(%s)",
624 "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()",
625 IDB_LOG_ID_STRING(),
626 transaction->LoggingSerialNumber(),
627 request->LoggingSerialNumber(),
628 IDB_LOG_STRINGIFY(transaction->Database()),
629 IDB_LOG_STRINGIFY(transaction),
630 IDB_LOG_STRINGIFY(mObjectStore),
631 IDB_LOG_STRINGIFY(this),
632 IDB_LOG_STRINGIFY(keyRange));
633
634 transaction->StartRequest(request, params);
635
636 return request.forget();
637 }
638
639 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex)
640 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex)
641
642 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex)
643 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
644 NS_INTERFACE_MAP_ENTRY(nsISupports)
645 NS_INTERFACE_MAP_END
646
647 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
648
649 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex)
650 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
651 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath)
652 NS_IMPL_CYCLE_COLLECTION_TRACE_END
653
654 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
655 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
656 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
657 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
658
659 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex)
660 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
661
662 // Don't unlink mObjectStore!
663
664 tmp->mCachedKeyPath.setUndefined();
665
666 if (tmp->mRooted) {
667 mozilla::DropJSObjects(tmp);
668 tmp->mRooted = false;
669 }
670 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
671
672 JSObject*
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)673 IDBIndex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
674 {
675 return IDBIndexBinding::Wrap(aCx, this, aGivenProto);
676 }
677
678 } // namespace dom
679 } // namespace mozilla
680