LCOV - code coverage report
Current view: top level - js/public - GCHashTable.h (source / functions) Hit Total Coverage
Test: output.info Lines: 91 244 37.3 %
Date: 2017-07-14 16:53:18 Functions: 99 332 29.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       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             : #ifndef GCHashTable_h
       8             : #define GCHashTable_h
       9             : 
      10             : #include "mozilla/Maybe.h"
      11             : 
      12             : #include "js/GCPolicyAPI.h"
      13             : #include "js/HashTable.h"
      14             : #include "js/RootingAPI.h"
      15             : #include "js/SweepingAPI.h"
      16             : #include "js/TracingAPI.h"
      17             : 
      18             : namespace JS {
      19             : 
      20             : // Define a reasonable default GC policy for GC-aware Maps.
      21             : template <typename Key, typename Value>
      22             : struct DefaultMapSweepPolicy {
      23           0 :     static bool needsSweep(Key* key, Value* value) {
      24           0 :         return GCPolicy<Key>::needsSweep(key) || GCPolicy<Value>::needsSweep(value);
      25             :     }
      26             : };
      27             : 
      28             : // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and
      29             : // sweep methods that know how to visit all keys and values in the table.
      30             : // HashMaps that contain GC pointers will generally want to use this GCHashMap
      31             : // specialization instead of HashMap, because this conveniently supports tracing
      32             : // keys and values, and cleaning up weak entries.
      33             : //
      34             : // GCHashMap::trace applies GCPolicy<T>::trace to each entry's key and value.
      35             : // Most types of GC pointers already have appropriate specializations of
      36             : // GCPolicy, so they should just work as keys and values. Any struct type with a
      37             : // default constructor and trace and sweep functions should work as well. If you
      38             : // need to define your own GCPolicy specialization, generic helpers can be found
      39             : // in js/public/TracingAPI.h.
      40             : //
      41             : // The MapSweepPolicy template parameter controls how the table drops entries
      42             : // when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table
      43             : // entry; if it returns true, the entry is dropped. The default MapSweepPolicy
      44             : // drops the entry if either the key or value is about to be finalized,
      45             : // according to its GCPolicy<T>::needsSweep method. (This default is almost
      46             : // always fine: it's hard to imagine keeping such an entry around anyway.)
      47             : //
      48             : // Note that this HashMap only knows *how* to trace and sweep, but it does not
      49             : // itself cause tracing or sweeping to be invoked. For tracing, it must be used
      50             : // with Rooted or PersistentRooted, or barriered and traced manually. For
      51             : // sweeping, currently it requires an explicit call to <map>.sweep().
      52             : template <typename Key,
      53             :           typename Value,
      54             :           typename HashPolicy = js::DefaultHasher<Key>,
      55             :           typename AllocPolicy = js::TempAllocPolicy,
      56             :           typename MapSweepPolicy = DefaultMapSweepPolicy<Key, Value>>
      57        3222 : class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy>
      58             : {
      59             :     using Base = js::HashMap<Key, Value, HashPolicy, AllocPolicy>;
      60             : 
      61             :   public:
      62        3885 :     explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a)  {}
      63             : 
      64             :     static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); }
      65          55 :     void trace(JSTracer* trc) {
      66          55 :         if (!this->initialized())
      67           1 :             return;
      68          54 :         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
      69           0 :             GCPolicy<Value>::trace(trc, &e.front().value(), "hashmap value");
      70           0 :             GCPolicy<Key>::trace(trc, &e.front().mutableKey(), "hashmap key");
      71             :         }
      72             :     }
      73             : 
      74           0 :     bool needsSweep() const {
      75           0 :         return this->initialized() && !this->empty();
      76             :     }
      77             : 
      78           0 :     void sweep() {
      79           0 :         if (!this->initialized())
      80           0 :             return;
      81             : 
      82           0 :         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
      83           0 :             if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value()))
      84           0 :                 e.removeFront();
      85             :         }
      86             :     }
      87             : 
      88             :     // GCHashMap is movable
      89        3117 :     GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {}
      90           0 :     void operator=(GCHashMap&& rhs) {
      91           0 :         MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
      92           0 :         Base::operator=(mozilla::Move(rhs));
      93           0 :     }
      94             : 
      95             :   private:
      96             :     // GCHashMap is not copyable or assignable
      97             :     GCHashMap(const GCHashMap& hm) = delete;
      98             :     GCHashMap& operator=(const GCHashMap& hm) = delete;
      99             : };
     100             : 
     101             : } // namespace JS
     102             : 
     103             : namespace js {
     104             : 
     105             : // HashMap that supports rekeying.
     106             : //
     107             : // If your keys are pointers to something like JSObject that can be tenured or
     108             : // compacted, prefer to use GCHashMap with MovableCellHasher, which takes
     109             : // advantage of the Zone's stable id table to make rekeying unnecessary.
     110             : template <typename Key,
     111             :           typename Value,
     112             :           typename HashPolicy = DefaultHasher<Key>,
     113             :           typename AllocPolicy = TempAllocPolicy,
     114             :           typename MapSweepPolicy = JS::DefaultMapSweepPolicy<Key, Value>>
     115        3074 : class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>
     116             : {
     117             :     using Base = JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy>;
     118             : 
     119             :   public:
     120        1734 :     explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a)  {}
     121             : 
     122           0 :     void sweep() {
     123           0 :         if (!this->initialized())
     124           0 :             return;
     125             : 
     126           0 :         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
     127           0 :             Key key(e.front().key());
     128           0 :             if (MapSweepPolicy::needsSweep(&key, &e.front().value()))
     129           0 :                 e.removeFront();
     130           0 :             else if (!HashPolicy::match(key, e.front().key()))
     131           0 :                 e.rekeyFront(key);
     132             :         }
     133             :     }
     134             : 
     135             :     // GCRekeyableHashMap is movable
     136        3043 :     GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(mozilla::Move(rhs)) {}
     137           0 :     void operator=(GCRekeyableHashMap&& rhs) {
     138           0 :         MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
     139           0 :         Base::operator=(mozilla::Move(rhs));
     140           0 :     }
     141             : };
     142             : 
     143             : template <typename Wrapper, typename... Args>
     144          74 : class WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
     145             : {
     146             :     using Map = JS::GCHashMap<Args...>;
     147             :     using Lookup = typename Map::Lookup;
     148             : 
     149        1860 :     const Map& map() const { return static_cast<const Wrapper*>(this)->get(); }
     150             : 
     151             :   public:
     152             :     using AddPtr = typename Map::AddPtr;
     153             :     using Ptr = typename Map::Ptr;
     154             :     using Range = typename Map::Range;
     155             : 
     156             :     bool initialized() const                   { return map().initialized(); }
     157           0 :     Ptr lookup(const Lookup& l) const          { return map().lookup(l); }
     158         154 :     AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); }
     159             :     Range all() const                          { return map().all(); }
     160             :     bool empty() const                         { return map().empty(); }
     161         308 :     uint32_t count() const                     { return map().count(); }
     162             :     size_t capacity() const                    { return map().capacity(); }
     163        1398 :     bool has(const Lookup& l) const            { return map().lookup(l).found(); }
     164             :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     165             :         return map().sizeOfExcludingThis(mallocSizeOf);
     166             :     }
     167             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     168             :         return mallocSizeOf(this) + map().sizeOfExcludingThis(mallocSizeOf);
     169             :     }
     170             : };
     171             : 
     172             : template <typename Wrapper, typename... Args>
     173          74 : class MutableWrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
     174             :   : public WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
     175             : {
     176             :     using Map = JS::GCHashMap<Args...>;
     177             :     using Lookup = typename Map::Lookup;
     178             : 
     179         302 :     Map& map() { return static_cast<Wrapper*>(this)->get(); }
     180             : 
     181             :   public:
     182             :     using AddPtr = typename Map::AddPtr;
     183             :     struct Enum : public Map::Enum { explicit Enum(Wrapper& o) : Map::Enum(o.map()) {} };
     184             :     using Ptr = typename Map::Ptr;
     185             :     using Range = typename Map::Range;
     186             : 
     187          74 :     bool init(uint32_t len = 16) { return map().init(len); }
     188          74 :     void clear()                 { map().clear(); }
     189             :     void finish()                { map().finish(); }
     190           0 :     void remove(Ptr p)           { map().remove(p); }
     191             : 
     192             :     template<typename KeyInput, typename ValueInput>
     193         154 :     bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
     194         154 :         return map().add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     195             :     }
     196             : 
     197             :     template<typename KeyInput>
     198             :     bool add(AddPtr& p, KeyInput&& k) {
     199             :         return map().add(p, mozilla::Forward<KeyInput>(k), Map::Value());
     200             :     }
     201             : 
     202             :     template<typename KeyInput, typename ValueInput>
     203             :     bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
     204             :         return map().relookupOrAdd(p, k,
     205             :                                    mozilla::Forward<KeyInput>(k),
     206             :                                    mozilla::Forward<ValueInput>(v));
     207             :     }
     208             : 
     209             :     template<typename KeyInput, typename ValueInput>
     210           0 :     bool put(KeyInput&& k, ValueInput&& v) {
     211           0 :         return map().put(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     212             :     }
     213             : 
     214             :     template<typename KeyInput, typename ValueInput>
     215             :     bool putNew(KeyInput&& k, ValueInput&& v) {
     216             :         return map().putNew(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
     217             :     }
     218             : };
     219             : 
     220             : } // namespace js
     221             : 
     222             : namespace JS {
     223             : 
     224             : // A GCHashSet is a HashSet with an additional trace method that knows
     225             : // be traced to be kept alive will generally want to use this GCHashSet
     226             : // specialization in lieu of HashSet.
     227             : //
     228             : // Most types of GC pointers can be traced with no extra infrastructure. For
     229             : // structs and non-gc-pointer members, ensure that there is a specialization of
     230             : // GCPolicy<T> with an appropriate trace method available to handle the custom
     231             : // type. Generic helpers can be found in js/public/TracingAPI.h.
     232             : //
     233             : // Note that although this HashSet's trace will deal correctly with moved
     234             : // elements, it does not itself know when to barrier or trace elements. To
     235             : // function properly it must either be used with Rooted or barriered and traced
     236             : // manually.
     237             : template <typename T,
     238             :           typename HashPolicy = js::DefaultHasher<T>,
     239             :           typename AllocPolicy = js::TempAllocPolicy>
     240         148 : class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
     241             : {
     242             :     using Base = js::HashSet<T, HashPolicy, AllocPolicy>;
     243             : 
     244             :   public:
     245        1504 :     explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a)  {}
     246             : 
     247             :     static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); }
     248          29 :     void trace(JSTracer* trc) {
     249          29 :         if (!this->initialized())
     250           3 :             return;
     251          33 :         for (typename Base::Enum e(*this); !e.empty(); e.popFront())
     252           7 :             GCPolicy<T>::trace(trc, &e.mutableFront(), "hashset element");
     253             :     }
     254             : 
     255           0 :     bool needsSweep() const {
     256           0 :         return this->initialized() && !this->empty();
     257             :     }
     258             : 
     259           0 :     void sweep() {
     260           0 :         if (!this->initialized())
     261           0 :             return;
     262           0 :         for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
     263           0 :             if (GCPolicy<T>::needsSweep(&e.mutableFront()))
     264           0 :                 e.removeFront();
     265             :         }
     266             :     }
     267             : 
     268             :     // GCHashSet is movable
     269          74 :     GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {}
     270             :     void operator=(GCHashSet&& rhs) {
     271             :         MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
     272             :         Base::operator=(mozilla::Move(rhs));
     273             :     }
     274             : 
     275             :   private:
     276             :     // GCHashSet is not copyable or assignable
     277             :     GCHashSet(const GCHashSet& hs) = delete;
     278             :     GCHashSet& operator=(const GCHashSet& hs) = delete;
     279             : };
     280             : 
     281             : } // namespace JS
     282             : 
     283             : namespace js {
     284             : 
     285             : template <typename Wrapper, typename... Args>
     286          74 : class WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
     287             : {
     288             :     using Set = JS::GCHashSet<Args...>;
     289             : 
     290         222 :     const Set& set() const { return static_cast<const Wrapper*>(this)->get(); }
     291             : 
     292             :   public:
     293             :     using Lookup = typename Set::Lookup;
     294             :     using AddPtr = typename Set::AddPtr;
     295             :     using Entry = typename Set::Entry;
     296             :     using Ptr = typename Set::Ptr;
     297             :     using Range = typename Set::Range;
     298             : 
     299          74 :     bool initialized() const                   { return set().initialized(); }
     300           0 :     Ptr lookup(const Lookup& l) const          { return set().lookup(l); }
     301           0 :     AddPtr lookupForAdd(const Lookup& l) const { return set().lookupForAdd(l); }
     302           0 :     Range all() const                          { return set().all(); }
     303         148 :     bool empty() const                         { return set().empty(); }
     304           0 :     uint32_t count() const                     { return set().count(); }
     305             :     size_t capacity() const                    { return set().capacity(); }
     306             :     bool has(const Lookup& l) const            { return set().lookup(l).found(); }
     307             :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     308             :         return set().sizeOfExcludingThis(mallocSizeOf);
     309             :     }
     310             :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     311             :         return mallocSizeOf(this) + set().sizeOfExcludingThis(mallocSizeOf);
     312             :     }
     313             : };
     314             : 
     315             : template <typename Wrapper, typename... Args>
     316          74 : class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
     317             :   : public WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
     318             : {
     319             :     using Set = JS::GCHashSet<Args...>;
     320             :     using Lookup = typename Set::Lookup;
     321             : 
     322          74 :     Set& set() { return static_cast<Wrapper*>(this)->get(); }
     323             : 
     324             :   public:
     325             :     using AddPtr = typename Set::AddPtr;
     326             :     using Entry = typename Set::Entry;
     327             :     struct Enum : public Set::Enum { explicit Enum(Wrapper& o) : Set::Enum(o.set()) {} };
     328             :     using Ptr = typename Set::Ptr;
     329             :     using Range = typename Set::Range;
     330             : 
     331          74 :     bool init(uint32_t len = 16) { return set().init(len); }
     332             :     void clear()                 { set().clear(); }
     333             :     void finish()                { set().finish(); }
     334           0 :     void remove(Ptr p)           { set().remove(p); }
     335             :     void remove(const Lookup& l) { set().remove(l); }
     336             : 
     337             :     template<typename TInput>
     338           0 :     bool add(AddPtr& p, TInput&& t) {
     339           0 :         return set().add(p, mozilla::Forward<TInput>(t));
     340             :     }
     341             : 
     342             :     template<typename TInput>
     343             :     bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
     344             :         return set().relookupOrAdd(p, l, mozilla::Forward<TInput>(t));
     345             :     }
     346             : 
     347             :     template<typename TInput>
     348           0 :     bool put(TInput&& t) {
     349           0 :         return set().put(mozilla::Forward<TInput>(t));
     350             :     }
     351             : 
     352             :     template<typename TInput>
     353             :     bool putNew(TInput&& t) {
     354             :         return set().putNew(mozilla::Forward<TInput>(t));
     355             :     }
     356             : 
     357             :     template<typename TInput>
     358             :     bool putNew(const Lookup& l, TInput&& t) {
     359             :         return set().putNew(l, mozilla::Forward<TInput>(t));
     360             :     }
     361             : };
     362             : 
     363             : } /* namespace js */
     364             : 
     365             : namespace JS {
     366             : 
     367             : // Specialize WeakCache for GCHashMap to provide a barriered map that does not
     368             : // need to be swept immediately.
     369             : template <typename Key, typename Value,
     370             :           typename HashPolicy, typename AllocPolicy, typename MapSweepPolicy>
     371             : class WeakCache<GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>>
     372             :   : protected detail::WeakCacheBase
     373             : {
     374             :     using Map = GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>;
     375             :     using Self = WeakCache<Map>;
     376             : 
     377             :     Map map;
     378             :     bool needsBarrier;
     379             : 
     380             :   public:
     381             :     template <typename... Args>
     382         272 :     explicit WeakCache(Zone* zone, Args&&... args)
     383         272 :       : WeakCacheBase(zone), map(mozilla::Forward<Args>(args)...), needsBarrier(false)
     384         272 :     {}
     385             :     template <typename... Args>
     386             :     explicit WeakCache(JSRuntime* rt, Args&&... args)
     387             :       : WeakCacheBase(rt), map(mozilla::Forward<Args>(args)...), needsBarrier(false)
     388             :     {}
     389           0 :     ~WeakCache() {
     390           0 :         MOZ_ASSERT(!needsBarrier);
     391           0 :     }
     392             : 
     393           0 :     bool needsSweep() override {
     394           0 :         return map.needsSweep();
     395             :     }
     396             : 
     397           0 :     size_t sweep() override {
     398           0 :         if (!this->initialized())
     399           0 :             return 0;
     400             : 
     401           0 :         size_t steps = map.count();
     402           0 :         map.sweep();
     403           0 :         return steps;
     404             :     }
     405             : 
     406           0 :     bool setNeedsIncrementalBarrier(bool needs) override {
     407           0 :         MOZ_ASSERT(needsBarrier != needs);
     408           0 :         needsBarrier = needs;
     409           0 :         return true;
     410             :     }
     411             : 
     412           0 :     bool needsIncrementalBarrier() const override {
     413           0 :         return needsBarrier;
     414             :     }
     415             : 
     416             :   private:
     417             :     using Entry = typename Map::Entry;
     418             : 
     419           0 :     static bool entryNeedsSweep(const Entry& prior) {
     420           0 :         Key key(prior.key());
     421           0 :         Value value(prior.value());
     422           0 :         bool result = MapSweepPolicy::needsSweep(&key, &value);
     423           0 :         MOZ_ASSERT(prior.key() == key); // We shouldn't update here.
     424           0 :         MOZ_ASSERT(prior.value() == value); // We shouldn't update here.
     425           0 :         return result;
     426             :     }
     427             : 
     428             :   public:
     429             :     using Lookup = typename Map::Lookup;
     430             :     using Ptr = typename Map::Ptr;
     431             :     using AddPtr = typename Map::AddPtr;
     432             : 
     433             :     struct Range
     434             :     {
     435           0 :         explicit Range(const typename Map::Range& r)
     436           0 :           : range(r)
     437             :         {
     438           0 :             settle();
     439           0 :         }
     440             :         Range() {}
     441             : 
     442           0 :         bool empty() const { return range.empty(); }
     443           0 :         const Entry& front() const { return range.front(); }
     444             : 
     445           0 :         void popFront() {
     446           0 :             range.popFront();
     447           0 :             settle();
     448           0 :         }
     449             : 
     450             :       private:
     451             :         typename Map::Range range;
     452             : 
     453           0 :         void settle() {
     454           0 :             while (!empty() && entryNeedsSweep(front()))
     455           0 :                 popFront();
     456           0 :         }
     457             :     };
     458             : 
     459             :     struct Enum : public Map::Enum
     460             :     {
     461             :         explicit Enum(Self& cache)
     462             :           : Map::Enum(cache.map)
     463             :         {
     464             :             // This operation is not allowed while barriers are in place as we
     465             :             // may also need to enumerate the set for sweeping.
     466             :             MOZ_ASSERT(!cache.needsBarrier);
     467             :         }
     468             :     };
     469             : 
     470           0 :     bool initialized() const {
     471           0 :         return map.initialized();
     472             :     }
     473             : 
     474           4 :     Ptr lookup(const Lookup& l) const {
     475           4 :         Ptr ptr = map.lookup(l);
     476           4 :         if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
     477           0 :             const_cast<Map&>(map).remove(ptr);
     478           0 :             return Ptr();
     479             :         }
     480           4 :         return ptr;
     481             :     }
     482             : 
     483        5031 :     AddPtr lookupForAdd(const Lookup& l) const {
     484        5031 :         AddPtr ptr = map.lookupForAdd(l);
     485        5031 :         if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
     486           0 :             const_cast<Map&>(map).remove(ptr);
     487           0 :             return map.lookupForAdd(l);
     488             :         }
     489        5031 :         return ptr;
     490             :     }
     491             : 
     492           0 :     Range all() const {
     493           0 :         return Range(map.all());
     494             :     }
     495             : 
     496             :     bool empty() const {
     497             :         // This operation is not currently allowed while barriers are in place
     498             :         // as it would require iterating the map and the caller expects a
     499             :         // constant time operation.
     500             :         MOZ_ASSERT(!needsBarrier);
     501             :         return map.empty();
     502             :     }
     503             : 
     504             :     uint32_t count() const {
     505             :         // This operation is not currently allowed while barriers are in place
     506             :         // as it would require iterating the set and the caller expects a
     507             :         // constant time operation.
     508             :         MOZ_ASSERT(!needsBarrier);
     509             :         return map.count();
     510             :     }
     511             : 
     512             :     size_t capacity() const {
     513             :         return map.capacity();
     514             :     }
     515             : 
     516             :     bool has(const Lookup& l) const {
     517             :         return lookup(l).found();
     518             :     }
     519             : 
     520             :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     521             :         return map.sizeOfExcludingThis(mallocSizeOf);
     522             :     }
     523           0 :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     524           0 :         return mallocSizeOf(this) + map.sizeOfExcludingThis(mallocSizeOf);
     525             :     }
     526             : 
     527         272 :     bool init(uint32_t len = 16) {
     528         272 :         MOZ_ASSERT(!needsBarrier);
     529         272 :         return map.init(len);
     530             :     }
     531             : 
     532           0 :     void clear() {
     533             :         // This operation is not currently allowed while barriers are in place
     534             :         // since it doesn't make sense to clear a cache while it is being swept.
     535           0 :         MOZ_ASSERT(!needsBarrier);
     536           0 :         map.clear();
     537           0 :     }
     538             : 
     539             :     void finish() {
     540             :         // This operation is not currently allowed while barriers are in place
     541             :         // since it doesn't make sense to destroy a cache while it is being swept.
     542             :         MOZ_ASSERT(!needsBarrier);
     543             :         map.finish();
     544             :     }
     545             : 
     546           4 :     void remove(Ptr p) {
     547             :         // This currently supports removing entries during incremental
     548             :         // sweeping. If we allow these tables to be swept incrementally this may
     549             :         // no longer be possible.
     550           4 :         map.remove(p);
     551           4 :     }
     552             : 
     553             :     void remove(const Lookup& l) {
     554             :         Ptr p = lookup(l);
     555             :         if (p)
     556             :             remove(p);
     557             :     }
     558             : 
     559             :     template<typename KeyInput>
     560             :     bool add(AddPtr& p, KeyInput&& k) {
     561             :         using mozilla::Forward;
     562             :         return map.add(p, Forward<KeyInput>(k));
     563             :     }
     564             : 
     565             :     template<typename KeyInput, typename ValueInput>
     566        2059 :     bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
     567             :         using mozilla::Forward;
     568        2059 :         return map.add(p, Forward<KeyInput>(k), Forward<ValueInput>(v));
     569             :     }
     570             : 
     571             :     template<typename KeyInput, typename ValueInput>
     572             :     bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
     573             :         using mozilla::Forward;
     574             :         return map.relookupOrAdd(p, Forward<KeyInput>(k), Forward<ValueInput>(v));
     575             :     }
     576             : 
     577             :     template<typename KeyInput, typename ValueInput>
     578             :     bool put(KeyInput&& k, ValueInput&& v) {
     579             :         using mozilla::Forward;
     580             :         return map.put(Forward<KeyInput>(k), Forward<ValueInput>(v));
     581             :     }
     582             : 
     583             :     template<typename KeyInput, typename ValueInput>
     584           4 :     bool putNew(KeyInput&& k, ValueInput&& v) {
     585             :         using mozilla::Forward;
     586           4 :         return map.putNew(Forward<KeyInput>(k), Forward<ValueInput>(v));
     587             :     }
     588             : };
     589             : 
     590             : // Specialize WeakCache for GCHashSet to provide a barriered set that does not
     591             : // need to be swept immediately.
     592             : template <typename T, typename HashPolicy, typename AllocPolicy>
     593           0 : class WeakCache<GCHashSet<T, HashPolicy, AllocPolicy>>
     594             :     : protected detail::WeakCacheBase
     595             : {
     596             :     using Set = GCHashSet<T, HashPolicy, AllocPolicy>;
     597             :     using Self = WeakCache<Set>;
     598             : 
     599             :     Set set;
     600             :     bool needsBarrier;
     601             : 
     602             :   public:
     603             :     using Entry = typename Set::Entry;
     604             : 
     605             :     template <typename... Args>
     606         746 :     explicit WeakCache(Zone* zone, Args&&... args)
     607         746 :       : WeakCacheBase(zone), set(mozilla::Forward<Args>(args)...), needsBarrier(false)
     608         746 :     {}
     609             :     template <typename... Args>
     610             :     explicit WeakCache(JSRuntime* rt, Args&&... args)
     611             :       : WeakCacheBase(rt), set(mozilla::Forward<Args>(args)...), needsBarrier(false)
     612             :     {}
     613             : 
     614           0 :     size_t sweep() override {
     615           0 :         if (!this->initialized())
     616           0 :             return 0;
     617             : 
     618           0 :         size_t steps = set.count();
     619           0 :         set.sweep();
     620           0 :         return steps;
     621             :     }
     622             : 
     623           0 :     bool needsSweep() override {
     624           0 :         return set.needsSweep();
     625             :     }
     626             : 
     627           0 :     bool setNeedsIncrementalBarrier(bool needs) override {
     628           0 :         MOZ_ASSERT(needsBarrier != needs);
     629           0 :         needsBarrier = needs;
     630           0 :         return true;
     631             :     }
     632             : 
     633           0 :     bool needsIncrementalBarrier() const override {
     634           0 :         return needsBarrier;
     635             :     }
     636             : 
     637             :   private:
     638           0 :    static bool entryNeedsSweep(const Entry& prior) {
     639           0 :         Entry entry(prior);
     640           0 :         bool result = GCPolicy<T>::needsSweep(&entry);
     641           0 :         MOZ_ASSERT(prior == entry); // We shouldn't update here.
     642           0 :         return result;
     643             :     }
     644             : 
     645             :   public:
     646             :     using Lookup = typename Set::Lookup;
     647             :     using Ptr = typename Set::Ptr;
     648             :     using AddPtr = typename Set::AddPtr;
     649             : 
     650             :     struct Range
     651             :     {
     652           0 :         explicit Range(const typename Set::Range& r)
     653           0 :           : range(r)
     654             :         {
     655           0 :             settle();
     656           0 :         }
     657             :         Range() {}
     658             : 
     659           0 :         bool empty() const { return range.empty(); }
     660           0 :         const Entry& front() const { return range.front(); }
     661             : 
     662           0 :         void popFront() {
     663           0 :             range.popFront();
     664           0 :             settle();
     665           0 :         }
     666             : 
     667             :       private:
     668             :         typename Set::Range range;
     669             : 
     670           0 :         void settle() {
     671           0 :             while (!empty() && entryNeedsSweep(front()))
     672           0 :                 popFront();
     673           0 :         }
     674             :     };
     675             : 
     676           0 :     struct Enum : public Set::Enum
     677             :     {
     678           0 :         explicit Enum(Self& cache)
     679           0 :           : Set::Enum(cache.set)
     680             :         {
     681             :             // This operation is not allowed while barriers are in place as we
     682             :             // may also need to enumerate the set for sweeping.
     683           0 :             MOZ_ASSERT(!cache.needsBarrier);
     684           0 :         }
     685             :     };
     686             : 
     687      157424 :     bool initialized() const {
     688      157424 :         return set.initialized();
     689             :     }
     690             : 
     691         994 :     Ptr lookup(const Lookup& l) const {
     692         994 :         Ptr ptr = set.lookup(l);
     693         994 :         if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
     694           0 :             const_cast<Set&>(set).remove(ptr);
     695           0 :             return Ptr();
     696             :         }
     697         994 :         return ptr;
     698             :     }
     699             : 
     700      278190 :     AddPtr lookupForAdd(const Lookup& l) const {
     701      278190 :         AddPtr ptr = set.lookupForAdd(l);
     702      278194 :         if (needsBarrier && ptr && entryNeedsSweep(*ptr)) {
     703           0 :             const_cast<Set&>(set).remove(ptr);
     704           0 :             return set.lookupForAdd(l);
     705             :         }
     706      278194 :         return ptr;
     707             :     }
     708             : 
     709           0 :     Range all() const {
     710           0 :         return Range(set.all());
     711             :     }
     712             : 
     713          15 :     bool empty() const {
     714             :         // This operation is not currently allowed while barriers are in place
     715             :         // as it would require iterating the set and the caller expects a
     716             :         // constant time operation.
     717          15 :         MOZ_ASSERT(!needsBarrier);
     718          15 :         return set.empty();
     719             :     }
     720             : 
     721             :     uint32_t count() 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.count();
     727             :     }
     728             : 
     729             :     size_t capacity() const {
     730             :         return set.capacity();
     731             :     }
     732             : 
     733             :     bool has(const Lookup& l) const {
     734             :         return lookup(l).found();
     735             :     }
     736             : 
     737           0 :     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     738           0 :         return set.sizeOfExcludingThis(mallocSizeOf);
     739             :     }
     740           0 :     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
     741           0 :         return mallocSizeOf(this) + set.sizeOfExcludingThis(mallocSizeOf);
     742             :     }
     743             : 
     744         738 :     bool init(uint32_t len = 16) {
     745         738 :         MOZ_ASSERT(!needsBarrier);
     746         738 :         return set.init(len);
     747             :     }
     748             : 
     749          60 :     void clear() {
     750             :         // This operation is not currently allowed while barriers are in place
     751             :         // since it doesn't make sense to clear a cache while it is being swept.
     752          60 :         MOZ_ASSERT(!needsBarrier);
     753          60 :         set.clear();
     754          60 :     }
     755             : 
     756             :     void finish() {
     757             :         // This operation is not currently allowed while barriers are in place
     758             :         // since it doesn't make sense to destroy a cache while it is being swept.
     759             :         MOZ_ASSERT(!needsBarrier);
     760             :         set.finish();
     761             :     }
     762             : 
     763           1 :     void remove(Ptr p) {
     764             :         // This currently supports removing entries during incremental
     765             :         // sweeping. If we allow these tables to be swept incrementally this may
     766             :         // no longer be possible.
     767           1 :         set.remove(p);
     768           1 :     }
     769             : 
     770             :     void remove(const Lookup& l) {
     771             :         Ptr p = lookup(l);
     772             :         if (p)
     773             :             remove(p);
     774             :     }
     775             : 
     776             :     template<typename TInput>
     777       13006 :     bool add(AddPtr& p, TInput&& t) {
     778       13006 :         return set.add(p, mozilla::Forward<TInput>(t));
     779             :     }
     780             : 
     781             :     template<typename TInput>
     782       13302 :     bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
     783       13302 :         return set.relookupOrAdd(p, l, mozilla::Forward<TInput>(t));
     784             :     }
     785             : 
     786             :     template<typename TInput>
     787          72 :     bool put(TInput&& t) {
     788          72 :         return set.put(mozilla::Forward<TInput>(t));
     789             :     }
     790             : 
     791             :     template<typename TInput>
     792           0 :     bool putNew(TInput&& t) {
     793           0 :         return set.putNew(mozilla::Forward<TInput>(t));
     794             :     }
     795             : 
     796             :     template<typename TInput>
     797           1 :     bool putNew(const Lookup& l, TInput&& t) {
     798           1 :         return set.putNew(l, mozilla::Forward<TInput>(t));
     799             :     }
     800             : };
     801             : 
     802             : } // namespace JS
     803             : 
     804             : #endif /* GCHashTable_h */

Generated by: LCOV version 1.13