[SM91] Update to Spidermonkey 91.1.3 APIs
[0ad.git] / libraries / source / spidermonkey / include-win32-debug / js / GCHashTable.h
blob9ca371193592ebfa9dfe063badcc8d03fa549b9a
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 #ifndef GCHashTable_h
8 #define GCHashTable_h
10 #include "mozilla/Maybe.h"
12 #include "js/GCPolicyAPI.h"
13 #include "js/HashTable.h"
14 #include "js/RootingAPI.h"
15 #include "js/SweepingAPI.h"
16 #include "js/TypeDecls.h"
18 class JSTracer;
20 namespace JS {
22 // Define a reasonable default GC policy for GC-aware Maps.
23 template <typename Key, typename Value>
24 struct DefaultMapSweepPolicy {
25 static bool needsSweep(Key* key, Value* value) {
26 return GCPolicy<Key>::needsSweep(key) || GCPolicy<Value>::needsSweep(value);
29 static bool traceWeak(JSTracer* trc, Key* key, Value* value) {
30 return GCPolicy<Key>::traceWeak(trc, key) &&
31 GCPolicy<Value>::traceWeak(trc, value);
35 // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and
36 // sweep methods that know how to visit all keys and values in the table.
37 // HashMaps that contain GC pointers will generally want to use this GCHashMap
38 // specialization instead of HashMap, because this conveniently supports tracing
39 // keys and values, and cleaning up weak entries.
41 // GCHashMap::trace applies GCPolicy<T>::trace to each entry's key and value.
42 // Most types of GC pointers already have appropriate specializations of
43 // GCPolicy, so they should just work as keys and values. Any struct type with a
44 // default constructor and trace and sweep functions should work as well. If you
45 // need to define your own GCPolicy specialization, generic helpers can be found
46 // in js/public/TracingAPI.h.
48 // The MapSweepPolicy template parameter controls how the table drops entries
49 // when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table
50 // entry; if it returns true, the entry is dropped. The default MapSweepPolicy
51 // drops the entry if either the key or value is about to be finalized,
52 // according to its GCPolicy<T>::needsSweep method. (This default is almost
53 // always fine: it's hard to imagine keeping such an entry around anyway.)
55 // Note that this HashMap only knows *how* to trace and sweep, but it does not
56 // itself cause tracing or sweeping to be invoked. For tracing, it must be used
57 // as Rooted<GCHashMap> or PersistentRooted<GCHashMap>, or barriered and traced
58 // manually. For sweeping, currently it requires an explicit call to
59 // <map>.sweep().
60 template <typename Key, typename Value,
61 typename HashPolicy = js::DefaultHasher<Key>,
62 typename AllocPolicy = js::TempAllocPolicy,
63 typename MapSweepPolicy = DefaultMapSweepPolicy<Key, Value>>
64 class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy> {
65 using Base = js::HashMap<Key, Value, HashPolicy, AllocPolicy>;
67 public:
68 explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(std::move(a)) {}
69 explicit GCHashMap(size_t length) : Base(length) {}
70 GCHashMap(AllocPolicy a, size_t length) : Base(std::move(a), length) {}
72 void trace(JSTracer* trc) {
73 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
74 GCPolicy<Value>::trace(trc, &e.front().value(), "hashmap value");
75 GCPolicy<Key>::trace(trc, &e.front().mutableKey(), "hashmap key");
79 bool needsSweep() const { return !this->empty(); }
81 void sweep() {
82 typename Base::Enum e(*this);
83 sweepEntries(e);
86 void sweepEntries(typename Base::Enum& e) {
87 for (; !e.empty(); e.popFront()) {
88 if (MapSweepPolicy::needsSweep(&e.front().mutableKey(),
89 &e.front().value())) {
90 e.removeFront();
95 void traceWeak(JSTracer* trc) {
96 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
97 if (!MapSweepPolicy::traceWeak(trc, &e.front().mutableKey(),
98 &e.front().value())) {
99 e.removeFront();
104 // GCHashMap is movable
105 GCHashMap(GCHashMap&& rhs) : Base(std::move(rhs)) {}
106 void operator=(GCHashMap&& rhs) {
107 MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
108 Base::operator=(std::move(rhs));
111 private:
112 // GCHashMap is not copyable or assignable
113 GCHashMap(const GCHashMap& hm) = delete;
114 GCHashMap& operator=(const GCHashMap& hm) = delete;
115 } MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS;
117 } // namespace JS
119 namespace js {
121 // HashMap that supports rekeying.
123 // If your keys are pointers to something like JSObject that can be tenured or
124 // compacted, prefer to use GCHashMap with MovableCellHasher, which takes
125 // advantage of the Zone's stable id table to make rekeying unnecessary.
126 template <typename Key, typename Value,
127 typename HashPolicy = DefaultHasher<Key>,
128 typename AllocPolicy = TempAllocPolicy,
129 typename MapSweepPolicy = JS::DefaultMapSweepPolicy<Key, Value>>
130 class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy,
131 AllocPolicy, MapSweepPolicy> {
132 using Base = JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy>;
134 public:
135 explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy())
136 : Base(std::move(a)) {}
137 explicit GCRekeyableHashMap(size_t length) : Base(length) {}
138 GCRekeyableHashMap(AllocPolicy a, size_t length)
139 : Base(std::move(a), length) {}
141 void sweep() {
142 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
143 Key key(e.front().key());
144 if (MapSweepPolicy::needsSweep(&key, &e.front().value())) {
145 e.removeFront();
146 } else if (!HashPolicy::match(key, e.front().key())) {
147 e.rekeyFront(key);
152 void traceWeak(JSTracer* trc) {
153 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
154 Key key(e.front().key());
155 if (!MapSweepPolicy::traceWeak(trc, &key, &e.front().value())) {
156 e.removeFront();
157 } else if (!HashPolicy::match(key, e.front().key())) {
158 e.rekeyFront(key);
163 // GCRekeyableHashMap is movable
164 GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(std::move(rhs)) {}
165 void operator=(GCRekeyableHashMap&& rhs) {
166 MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
167 Base::operator=(std::move(rhs));
169 } MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS;
171 template <typename Wrapper, typename... Args>
172 class WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper> {
173 using Map = JS::GCHashMap<Args...>;
174 using Lookup = typename Map::Lookup;
176 const Map& map() const { return static_cast<const Wrapper*>(this)->get(); }
178 public:
179 using AddPtr = typename Map::AddPtr;
180 using Ptr = typename Map::Ptr;
181 using Range = typename Map::Range;
183 Ptr lookup(const Lookup& l) const { return map().lookup(l); }
184 Range all() const { return map().all(); }
185 bool empty() const { return map().empty(); }
186 uint32_t count() const { return map().count(); }
187 size_t capacity() const { return map().capacity(); }
188 bool has(const Lookup& l) const { return map().lookup(l).found(); }
189 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
190 return map().sizeOfExcludingThis(mallocSizeOf);
192 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
193 return mallocSizeOf(this) + map().sizeOfExcludingThis(mallocSizeOf);
197 template <typename Wrapper, typename... Args>
198 class MutableWrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
199 : public WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper> {
200 using Map = JS::GCHashMap<Args...>;
201 using Lookup = typename Map::Lookup;
203 Map& map() { return static_cast<Wrapper*>(this)->get(); }
205 public:
206 using AddPtr = typename Map::AddPtr;
207 struct Enum : public Map::Enum {
208 explicit Enum(Wrapper& o) : Map::Enum(o.map()) {}
210 using Ptr = typename Map::Ptr;
211 using Range = typename Map::Range;
213 void clear() { map().clear(); }
214 void clearAndCompact() { map().clearAndCompact(); }
215 void remove(Ptr p) { map().remove(p); }
216 AddPtr lookupForAdd(const Lookup& l) { return map().lookupForAdd(l); }
218 template <typename KeyInput, typename ValueInput>
219 bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
220 return map().add(p, std::forward<KeyInput>(k), std::forward<ValueInput>(v));
223 template <typename KeyInput>
224 bool add(AddPtr& p, KeyInput&& k) {
225 return map().add(p, std::forward<KeyInput>(k), Map::Value());
228 template <typename KeyInput, typename ValueInput>
229 bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
230 return map().relookupOrAdd(p, k, std::forward<KeyInput>(k),
231 std::forward<ValueInput>(v));
234 template <typename KeyInput, typename ValueInput>
235 bool put(KeyInput&& k, ValueInput&& v) {
236 return map().put(std::forward<KeyInput>(k), std::forward<ValueInput>(v));
239 template <typename KeyInput, typename ValueInput>
240 bool putNew(KeyInput&& k, ValueInput&& v) {
241 return map().putNew(std::forward<KeyInput>(k), std::forward<ValueInput>(v));
245 } // namespace js
247 namespace JS {
249 // A GCHashSet is a HashSet with an additional trace method that knows
250 // be traced to be kept alive will generally want to use this GCHashSet
251 // specialization in lieu of HashSet.
253 // Most types of GC pointers can be traced with no extra infrastructure. For
254 // structs and non-gc-pointer members, ensure that there is a specialization of
255 // GCPolicy<T> with an appropriate trace method available to handle the custom
256 // type. Generic helpers can be found in js/public/TracingAPI.h.
258 // Note that although this HashSet's trace will deal correctly with moved
259 // elements, it does not itself know when to barrier or trace elements. To
260 // function properly it must either be used with Rooted or barriered and traced
261 // manually.
262 template <typename T, typename HashPolicy = js::DefaultHasher<T>,
263 typename AllocPolicy = js::TempAllocPolicy>
264 class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy> {
265 using Base = js::HashSet<T, HashPolicy, AllocPolicy>;
267 public:
268 explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(std::move(a)) {}
269 explicit GCHashSet(size_t length) : Base(length) {}
270 GCHashSet(AllocPolicy a, size_t length) : Base(std::move(a), length) {}
272 void trace(JSTracer* trc) {
273 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
274 GCPolicy<T>::trace(trc, &e.mutableFront(), "hashset element");
278 bool needsSweep() const { return !this->empty(); }
280 void sweep() {
281 typename Base::Enum e(*this);
282 sweepEntries(e);
285 void sweepEntries(typename Base::Enum& e) {
286 for (; !e.empty(); e.popFront()) {
287 if (GCPolicy<T>::needsSweep(&e.mutableFront())) {
288 e.removeFront();
293 void traceWeak(JSTracer* trc) {
294 for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
295 if (!GCPolicy<T>::traceWeak(trc, &e.mutableFront())) {
296 e.removeFront();
301 // GCHashSet is movable
302 GCHashSet(GCHashSet&& rhs) : Base(std::move(rhs)) {}
303 void operator=(GCHashSet&& rhs) {
304 MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
305 Base::operator=(std::move(rhs));
308 private:
309 // GCHashSet is not copyable or assignable
310 GCHashSet(const GCHashSet& hs) = delete;
311 GCHashSet& operator=(const GCHashSet& hs) = delete;
312 } MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS;
314 } // namespace JS
316 namespace js {
318 template <typename Wrapper, typename... Args>
319 class WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper> {
320 using Set = JS::GCHashSet<Args...>;
322 const Set& set() const { return static_cast<const Wrapper*>(this)->get(); }
324 public:
325 using Lookup = typename Set::Lookup;
326 using AddPtr = typename Set::AddPtr;
327 using Entry = typename Set::Entry;
328 using Ptr = typename Set::Ptr;
329 using Range = typename Set::Range;
331 Ptr lookup(const Lookup& l) const { return set().lookup(l); }
332 Range all() const { return set().all(); }
333 bool empty() const { return set().empty(); }
334 uint32_t count() const { return set().count(); }
335 size_t capacity() const { return set().capacity(); }
336 bool has(const Lookup& l) const { return set().lookup(l).found(); }
337 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
338 return set().sizeOfExcludingThis(mallocSizeOf);
340 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
341 return mallocSizeOf(this) + set().sizeOfExcludingThis(mallocSizeOf);
345 template <typename Wrapper, typename... Args>
346 class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
347 : public WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper> {
348 using Set = JS::GCHashSet<Args...>;
349 using Lookup = typename Set::Lookup;
351 Set& set() { return static_cast<Wrapper*>(this)->get(); }
353 public:
354 using AddPtr = typename Set::AddPtr;
355 using Entry = typename Set::Entry;
356 struct Enum : public Set::Enum {
357 explicit Enum(Wrapper& o) : Set::Enum(o.set()) {}
359 using Ptr = typename Set::Ptr;
360 using Range = typename Set::Range;
362 void clear() { set().clear(); }
363 void clearAndCompact() { set().clearAndCompact(); }
364 [[nodiscard]] bool reserve(uint32_t len) { return set().reserve(len); }
365 void remove(Ptr p) { set().remove(p); }
366 void remove(const Lookup& l) { set().remove(l); }
367 AddPtr lookupForAdd(const Lookup& l) { return set().lookupForAdd(l); }
369 template <typename TInput>
370 void replaceKey(Ptr p, const Lookup& l, TInput&& newValue) {
371 set().replaceKey(p, l, std::forward<TInput>(newValue));
374 template <typename TInput>
375 bool add(AddPtr& p, TInput&& t) {
376 return set().add(p, std::forward<TInput>(t));
379 template <typename TInput>
380 bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
381 return set().relookupOrAdd(p, l, std::forward<TInput>(t));
384 template <typename TInput>
385 bool put(TInput&& t) {
386 return set().put(std::forward<TInput>(t));
389 template <typename TInput>
390 bool putNew(TInput&& t) {
391 return set().putNew(std::forward<TInput>(t));
394 template <typename TInput>
395 bool putNew(const Lookup& l, TInput&& t) {
396 return set().putNew(l, std::forward<TInput>(t));
400 } /* namespace js */
402 namespace JS {
404 // Specialize WeakCache for GCHashMap to provide a barriered map that does not
405 // need to be swept immediately.
406 template <typename Key, typename Value, typename HashPolicy,
407 typename AllocPolicy, typename MapSweepPolicy>
408 class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
409 : protected detail::WeakCacheBase {
410 using Map = GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>;
411 using Self = WeakCache<Map>;
413 Map map;
414 bool needsBarrier;
416 public:
417 template <typename... Args>
418 explicit WeakCache(Zone* zone, Args&&... args)
419 : WeakCacheBase(zone),
420 map(std::forward<Args>(args)...),
421 needsBarrier(false) {}
422 template <typename... Args>
423 explicit WeakCache(JSRuntime* rt, Args&&... args)
424 : WeakCacheBase(rt),
425 map(std::forward<Args>(args)...),
426 needsBarrier(false) {}
427 ~WeakCache() { MOZ_ASSERT(!needsBarrier); }
429 bool needsSweep() override { return map.needsSweep(); }
431 size_t sweep(js::gc::StoreBuffer* sbToLock) override {
432 size_t steps = map.count();
434 // Create an Enum and sweep the table entries.
435 mozilla::Maybe<typename Map::Enum> e;
436 e.emplace(map);
437 map.sweepEntries(e.ref());
439 // Potentially take a lock while the Enum's destructor is called as this can
440 // rehash/resize the table and access the store buffer.
441 mozilla::Maybe<js::gc::AutoLockStoreBuffer> lock;
442 if (sbToLock) {
443 lock.emplace(sbToLock);
445 e.reset();
447 return steps;
450 bool setNeedsIncrementalBarrier(bool needs) override {
451 MOZ_ASSERT(needsBarrier != needs);
452 needsBarrier = needs;
453 return true;
456 bool needsIncrementalBarrier() const override { return needsBarrier; }
458 private:
459 using Entry = typename Map::Entry;
461 static bool entryNeedsSweep(const Entry& prior) {
462 Key key(prior.key());
463 Value value(prior.value());
464 bool result = MapSweepPolicy::needsSweep(&key, &value);
465 MOZ_ASSERT(prior.key() == key); // We shouldn't update here.
466 MOZ_ASSERT(prior.value() == value); // We shouldn't update here.
467 return result;
470 public:
471 using Lookup = typename Map::Lookup;
472 using Ptr = typename Map::Ptr;
473 using AddPtr = typename Map::AddPtr;
475 struct Range {
476 explicit Range(const typename Map::Range& r) : range(r) { settle(); }
477 Range() = default;
479 bool empty() const { return range.empty(); }
480 const Entry& front() const { return range.front(); }
482 void popFront() {
483 range.popFront();
484 settle();
487 private:
488 typename Map::Range range;
490 void settle() {
491 while (!empty() && entryNeedsSweep(front())) {
492 popFront();
497 struct Enum : public Map::Enum {
498 explicit Enum(Self& cache) : Map::Enum(cache.map) {
499 // This operation is not allowed while barriers are in place as we
500 // may also need to enumerate the set for sweeping.
501 MOZ_ASSERT(!cache.needsBarrier);
505 Ptr lookup(const Lookup& l) const {
506 Ptr ptr = map.lookup(l);
507 if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
508 const_cast<Map&>(map).remove(ptr);
509 return Ptr();
511 return ptr;
514 AddPtr lookupForAdd(const Lookup& l) {
515 AddPtr ptr = map.lookupForAdd(l);
516 if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
517 const_cast<Map&>(map).remove(ptr);
518 return map.lookupForAdd(l);
520 return ptr;
523 Range all() const { return Range(map.all()); }
525 bool empty() const {
526 // This operation is not currently allowed while barriers are in place
527 // as it would require iterating the map and the caller expects a
528 // constant time operation.
529 MOZ_ASSERT(!needsBarrier);
530 return map.empty();
533 uint32_t count() const {
534 // This operation is not currently allowed while barriers are in place
535 // as it would require iterating the set and the caller expects a
536 // constant time operation.
537 MOZ_ASSERT(!needsBarrier);
538 return map.count();
541 size_t capacity() const { return map.capacity(); }
543 bool has(const Lookup& l) const { return lookup(l).found(); }
545 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
546 return map.sizeOfExcludingThis(mallocSizeOf);
548 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
549 return mallocSizeOf(this) + map.shallowSizeOfExcludingThis(mallocSizeOf);
552 void clear() {
553 // This operation is not currently allowed while barriers are in place
554 // since it doesn't make sense to clear a cache while it is being swept.
555 MOZ_ASSERT(!needsBarrier);
556 map.clear();
559 void clearAndCompact() {
560 // This operation is not currently allowed while barriers are in place
561 // since it doesn't make sense to clear a cache while it is being swept.
562 MOZ_ASSERT(!needsBarrier);
563 map.clearAndCompact();
566 void remove(Ptr p) {
567 // This currently supports removing entries during incremental
568 // sweeping. If we allow these tables to be swept incrementally this may
569 // no longer be possible.
570 map.remove(p);
573 void remove(const Lookup& l) {
574 Ptr p = lookup(l);
575 if (p) {
576 remove(p);
580 template <typename KeyInput, typename ValueInput>
581 bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
582 return map.add(p, std::forward<KeyInput>(k), std::forward<ValueInput>(v));
585 template <typename KeyInput, typename ValueInput>
586 bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
587 return map.relookupOrAdd(p, std::forward<KeyInput>(k),
588 std::forward<ValueInput>(v));
591 template <typename KeyInput, typename ValueInput>
592 bool put(KeyInput&& k, ValueInput&& v) {
593 return map.put(std::forward<KeyInput>(k), std::forward<ValueInput>(v));
596 template <typename KeyInput, typename ValueInput>
597 bool putNew(KeyInput&& k, ValueInput&& v) {
598 return map.putNew(std::forward<KeyInput>(k), std::forward<ValueInput>(v));
600 } JS_HAZ_NON_GC_POINTER;
602 // Specialize WeakCache for GCHashSet to provide a barriered set that does not
603 // need to be swept immediately.
604 template <typename T, typename HashPolicy, typename AllocPolicy>
605 class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
606 : protected detail::WeakCacheBase {
607 using Set = GCHashSet<T, HashPolicy, AllocPolicy>;
608 using Self = WeakCache<Set>;
610 Set set;
611 bool needsBarrier;
613 public:
614 using Entry = typename Set::Entry;
616 template <typename... Args>
617 explicit WeakCache(Zone* zone, Args&&... args)
618 : WeakCacheBase(zone),
619 set(std::forward<Args>(args)...),
620 needsBarrier(false) {}
621 template <typename... Args>
622 explicit WeakCache(JSRuntime* rt, Args&&... args)
623 : WeakCacheBase(rt),
624 set(std::forward<Args>(args)...),
625 needsBarrier(false) {}
627 size_t sweep(js::gc::StoreBuffer* sbToLock) override {
628 size_t steps = set.count();
630 // Create an Enum and sweep the table entries. It's not necessary to take
631 // the store buffer lock yet.
632 mozilla::Maybe<typename Set::Enum> e;
633 e.emplace(set);
634 set.sweepEntries(e.ref());
636 // Destroy the Enum, potentially rehashing or resizing the table. Since this
637 // can access the store buffer, we need to take a lock for this if we're
638 // called off main thread.
639 mozilla::Maybe<js::gc::AutoLockStoreBuffer> lock;
640 if (sbToLock) {
641 lock.emplace(sbToLock);
643 e.reset();
645 return steps;
648 bool needsSweep() override { return set.needsSweep(); }
650 bool setNeedsIncrementalBarrier(bool needs) override {
651 MOZ_ASSERT(needsBarrier != needs);
652 needsBarrier = needs;
653 return true;
656 bool needsIncrementalBarrier() const override { return needsBarrier; }
658 private:
659 static bool entryNeedsSweep(const Entry& prior) {
660 Entry entry(prior);
661 bool result = GCPolicy<T>::needsSweep(&entry);
662 MOZ_ASSERT(prior == entry); // We shouldn't update here.
663 return result;
666 public:
667 using Lookup = typename Set::Lookup;
668 using Ptr = typename Set::Ptr;
669 using AddPtr = typename Set::AddPtr;
671 struct Range {
672 explicit Range(const typename Set::Range& r) : range(r) { settle(); }
673 Range() = default;
675 bool empty() const { return range.empty(); }
676 const Entry& front() const { return range.front(); }
678 void popFront() {
679 range.popFront();
680 settle();
683 private:
684 typename Set::Range range;
686 void settle() {
687 while (!empty() && entryNeedsSweep(front())) {
688 popFront();
693 struct Enum : public Set::Enum {
694 explicit Enum(Self& cache) : Set::Enum(cache.set) {
695 // This operation is not allowed while barriers are in place as we
696 // may also need to enumerate the set for sweeping.
697 MOZ_ASSERT(!cache.needsBarrier);
701 Ptr lookup(const Lookup& l) const {
702 Ptr ptr = set.lookup(l);
703 if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
704 const_cast<Set&>(set).remove(ptr);
705 return Ptr();
707 return ptr;
710 AddPtr lookupForAdd(const Lookup& l) {
711 AddPtr ptr = set.lookupForAdd(l);
712 if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
713 const_cast<Set&>(set).remove(ptr);
714 return set.lookupForAdd(l);
716 return ptr;
719 Range all() const { return Range(set.all()); }
721 bool empty() const {
722 // This operation is not currently allowed while barriers are in place
723 // as it would require iterating the set and the caller expects a
724 // constant time operation.
725 MOZ_ASSERT(!needsBarrier);
726 return set.empty();
729 uint32_t count() const {
730 // This operation is not currently allowed while barriers are in place
731 // as it would require iterating the set and the caller expects a
732 // constant time operation.
733 MOZ_ASSERT(!needsBarrier);
734 return set.count();
737 size_t capacity() const { return set.capacity(); }
739 bool has(const Lookup& l) const { return lookup(l).found(); }
741 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
742 return set.shallowSizeOfExcludingThis(mallocSizeOf);
744 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
745 return mallocSizeOf(this) + set.shallowSizeOfExcludingThis(mallocSizeOf);
748 void clear() {
749 // This operation is not currently allowed while barriers are in place
750 // since it doesn't make sense to clear a cache while it is being swept.
751 MOZ_ASSERT(!needsBarrier);
752 set.clear();
755 void clearAndCompact() {
756 // This operation is not currently allowed while barriers are in place
757 // since it doesn't make sense to clear a cache while it is being swept.
758 MOZ_ASSERT(!needsBarrier);
759 set.clearAndCompact();
762 void remove(Ptr p) {
763 // This currently supports removing entries during incremental
764 // sweeping. If we allow these tables to be swept incrementally this may
765 // no longer be possible.
766 set.remove(p);
769 void remove(const Lookup& l) {
770 Ptr p = lookup(l);
771 if (p) {
772 remove(p);
776 template <typename TInput>
777 void replaceKey(Ptr p, const Lookup& l, TInput&& newValue) {
778 set.replaceKey(p, l, std::forward<TInput>(newValue));
781 template <typename TInput>
782 bool add(AddPtr& p, TInput&& t) {
783 return set.add(p, std::forward<TInput>(t));
786 template <typename TInput>
787 bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
788 return set.relookupOrAdd(p, l, std::forward<TInput>(t));
791 template <typename TInput>
792 bool put(TInput&& t) {
793 return set.put(std::forward<TInput>(t));
796 template <typename TInput>
797 bool putNew(TInput&& t) {
798 return set.putNew(std::forward<TInput>(t));
801 template <typename TInput>
802 bool putNew(const Lookup& l, TInput&& t) {
803 return set.putNew(l, std::forward<TInput>(t));
805 } JS_HAZ_NON_GC_POINTER;
807 } // namespace JS
809 #endif /* GCHashTable_h */