GCHashTable.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef GCHashTable_h
  6. #define GCHashTable_h
  7. #include "js/GCPolicyAPI.h"
  8. #include "js/HashTable.h"
  9. #include "js/RootingAPI.h"
  10. #include "js/SweepingAPI.h"
  11. #include "js/TracingAPI.h"
  12. namespace JS {
  13. // Define a reasonable default GC policy for GC-aware Maps.
  14. template <typename Key, typename Value>
  15. struct DefaultMapSweepPolicy {
  16. static bool needsSweep(Key* key, Value* value) {
  17. return GCPolicy<Key>::needsSweep(key) || GCPolicy<Value>::needsSweep(value);
  18. }
  19. };
  20. // A GCHashMap is a GC-aware HashMap, meaning that it has additional trace and
  21. // sweep methods that know how to visit all keys and values in the table.
  22. // HashMaps that contain GC pointers will generally want to use this GCHashMap
  23. // specialization instead of HashMap, because this conveniently supports tracing
  24. // keys and values, and cleaning up weak entries.
  25. //
  26. // GCHashMap::trace applies GCPolicy<T>::trace to each entry's key and value.
  27. // Most types of GC pointers already have appropriate specializations of
  28. // GCPolicy, so they should just work as keys and values. Any struct type with a
  29. // default constructor and trace and sweep functions should work as well. If you
  30. // need to define your own GCPolicy specialization, generic helpers can be found
  31. // in js/public/TracingAPI.h.
  32. //
  33. // The MapSweepPolicy template parameter controls how the table drops entries
  34. // when swept. GCHashMap::sweep applies MapSweepPolicy::needsSweep to each table
  35. // entry; if it returns true, the entry is dropped. The default MapSweepPolicy
  36. // drops the entry if either the key or value is about to be finalized,
  37. // according to its GCPolicy<T>::needsSweep method. (This default is almost
  38. // always fine: it's hard to imagine keeping such an entry around anyway.)
  39. //
  40. // Note that this HashMap only knows *how* to trace and sweep, but it does not
  41. // itself cause tracing or sweeping to be invoked. For tracing, it must be used
  42. // with Rooted or PersistentRooted, or barriered and traced manually. For
  43. // sweeping, currently it requires an explicit call to <map>.sweep().
  44. template <typename Key,
  45. typename Value,
  46. typename HashPolicy = js::DefaultHasher<Key>,
  47. typename AllocPolicy = js::TempAllocPolicy,
  48. typename MapSweepPolicy = DefaultMapSweepPolicy<Key, Value>>
  49. class GCHashMap : public js::HashMap<Key, Value, HashPolicy, AllocPolicy>
  50. {
  51. using Base = js::HashMap<Key, Value, HashPolicy, AllocPolicy>;
  52. public:
  53. explicit GCHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {}
  54. static void trace(GCHashMap* map, JSTracer* trc) { map->trace(trc); }
  55. void trace(JSTracer* trc) {
  56. if (!this->initialized())
  57. return;
  58. for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
  59. GCPolicy<Value>::trace(trc, &e.front().value(), "hashmap value");
  60. GCPolicy<Key>::trace(trc, &e.front().mutableKey(), "hashmap key");
  61. }
  62. }
  63. void sweep() {
  64. if (!this->initialized())
  65. return;
  66. for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
  67. if (MapSweepPolicy::needsSweep(&e.front().mutableKey(), &e.front().value()))
  68. e.removeFront();
  69. }
  70. }
  71. // GCHashMap is movable
  72. GCHashMap(GCHashMap&& rhs) : Base(mozilla::Move(rhs)) {}
  73. void operator=(GCHashMap&& rhs) {
  74. MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
  75. Base::operator=(mozilla::Move(rhs));
  76. }
  77. private:
  78. // GCHashMap is not copyable or assignable
  79. GCHashMap(const GCHashMap& hm) = delete;
  80. GCHashMap& operator=(const GCHashMap& hm) = delete;
  81. };
  82. } // namespace JS
  83. namespace js {
  84. // HashMap that supports rekeying.
  85. //
  86. // If your keys are pointers to something like JSObject that can be tenured or
  87. // compacted, prefer to use GCHashMap with MovableCellHasher, which takes
  88. // advantage of the Zone's stable id table to make rekeying unnecessary.
  89. template <typename Key,
  90. typename Value,
  91. typename HashPolicy = DefaultHasher<Key>,
  92. typename AllocPolicy = TempAllocPolicy,
  93. typename MapSweepPolicy = JS::DefaultMapSweepPolicy<Key, Value>>
  94. class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy, MapSweepPolicy>
  95. {
  96. using Base = JS::GCHashMap<Key, Value, HashPolicy, AllocPolicy>;
  97. public:
  98. explicit GCRekeyableHashMap(AllocPolicy a = AllocPolicy()) : Base(a) {}
  99. void sweep() {
  100. if (!this->initialized())
  101. return;
  102. for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
  103. Key key(e.front().key());
  104. if (MapSweepPolicy::needsSweep(&key, &e.front().value()))
  105. e.removeFront();
  106. else if (!HashPolicy::match(key, e.front().key()))
  107. e.rekeyFront(key);
  108. }
  109. }
  110. // GCRekeyableHashMap is movable
  111. GCRekeyableHashMap(GCRekeyableHashMap&& rhs) : Base(mozilla::Move(rhs)) {}
  112. void operator=(GCRekeyableHashMap&& rhs) {
  113. MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
  114. Base::operator=(mozilla::Move(rhs));
  115. }
  116. };
  117. template <typename Outer, typename... Args>
  118. class GCHashMapOperations
  119. {
  120. using Map = JS::GCHashMap<Args...>;
  121. using Lookup = typename Map::Lookup;
  122. const Map& map() const { return static_cast<const Outer*>(this)->get(); }
  123. public:
  124. using AddPtr = typename Map::AddPtr;
  125. using Ptr = typename Map::Ptr;
  126. using Range = typename Map::Range;
  127. bool initialized() const { return map().initialized(); }
  128. Ptr lookup(const Lookup& l) const { return map().lookup(l); }
  129. AddPtr lookupForAdd(const Lookup& l) const { return map().lookupForAdd(l); }
  130. Range all() const { return map().all(); }
  131. bool empty() const { return map().empty(); }
  132. uint32_t count() const { return map().count(); }
  133. size_t capacity() const { return map().capacity(); }
  134. bool has(const Lookup& l) const { return map().lookup(l).found(); }
  135. size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  136. return map().sizeOfExcludingThis(mallocSizeOf);
  137. }
  138. size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  139. return mallocSizeOf(this) + map().sizeOfExcludingThis(mallocSizeOf);
  140. }
  141. };
  142. template <typename Outer, typename... Args>
  143. class MutableGCHashMapOperations
  144. : public GCHashMapOperations<Outer, Args...>
  145. {
  146. using Map = JS::GCHashMap<Args...>;
  147. using Lookup = typename Map::Lookup;
  148. Map& map() { return static_cast<Outer*>(this)->get(); }
  149. public:
  150. using AddPtr = typename Map::AddPtr;
  151. struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} };
  152. using Ptr = typename Map::Ptr;
  153. using Range = typename Map::Range;
  154. bool init(uint32_t len = 16) { return map().init(len); }
  155. void clear() { map().clear(); }
  156. void finish() { map().finish(); }
  157. void remove(Ptr p) { map().remove(p); }
  158. template<typename KeyInput, typename ValueInput>
  159. bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) {
  160. return map().add(p, mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
  161. }
  162. template<typename KeyInput>
  163. bool add(AddPtr& p, KeyInput&& k) {
  164. return map().add(p, mozilla::Forward<KeyInput>(k), Map::Value());
  165. }
  166. template<typename KeyInput, typename ValueInput>
  167. bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) {
  168. return map().relookupOrAdd(p, k,
  169. mozilla::Forward<KeyInput>(k),
  170. mozilla::Forward<ValueInput>(v));
  171. }
  172. template<typename KeyInput, typename ValueInput>
  173. bool put(KeyInput&& k, ValueInput&& v) {
  174. return map().put(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
  175. }
  176. template<typename KeyInput, typename ValueInput>
  177. bool putNew(KeyInput&& k, ValueInput&& v) {
  178. return map().putNew(mozilla::Forward<KeyInput>(k), mozilla::Forward<ValueInput>(v));
  179. }
  180. };
  181. template <typename A, typename B, typename C, typename D, typename E>
  182. class RootedBase<JS::GCHashMap<A,B,C,D,E>>
  183. : public MutableGCHashMapOperations<JS::Rooted<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
  184. {};
  185. template <typename A, typename B, typename C, typename D, typename E>
  186. class MutableHandleBase<JS::GCHashMap<A,B,C,D,E>>
  187. : public MutableGCHashMapOperations<JS::MutableHandle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
  188. {};
  189. template <typename A, typename B, typename C, typename D, typename E>
  190. class HandleBase<JS::GCHashMap<A,B,C,D,E>>
  191. : public GCHashMapOperations<JS::Handle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
  192. {};
  193. template <typename A, typename B, typename C, typename D, typename E>
  194. class WeakCacheBase<JS::GCHashMap<A,B,C,D,E>>
  195. : public MutableGCHashMapOperations<JS::WeakCache<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
  196. {};
  197. } // namespace js
  198. namespace JS {
  199. // A GCHashSet is a HashSet with an additional trace method that knows
  200. // be traced to be kept alive will generally want to use this GCHashSet
  201. // specialization in lieu of HashSet.
  202. //
  203. // Most types of GC pointers can be traced with no extra infrastructure. For
  204. // structs and non-gc-pointer members, ensure that there is a specialization of
  205. // GCPolicy<T> with an appropriate trace method available to handle the custom
  206. // type. Generic helpers can be found in js/public/TracingAPI.h.
  207. //
  208. // Note that although this HashSet's trace will deal correctly with moved
  209. // elements, it does not itself know when to barrier or trace elements. To
  210. // function properly it must either be used with Rooted or barriered and traced
  211. // manually.
  212. template <typename T,
  213. typename HashPolicy = js::DefaultHasher<T>,
  214. typename AllocPolicy = js::TempAllocPolicy>
  215. class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
  216. {
  217. using Base = js::HashSet<T, HashPolicy, AllocPolicy>;
  218. public:
  219. explicit GCHashSet(AllocPolicy a = AllocPolicy()) : Base(a) {}
  220. static void trace(GCHashSet* set, JSTracer* trc) { set->trace(trc); }
  221. void trace(JSTracer* trc) {
  222. if (!this->initialized())
  223. return;
  224. for (typename Base::Enum e(*this); !e.empty(); e.popFront())
  225. GCPolicy<T>::trace(trc, &e.mutableFront(), "hashset element");
  226. }
  227. void sweep() {
  228. if (!this->initialized())
  229. return;
  230. for (typename Base::Enum e(*this); !e.empty(); e.popFront()) {
  231. if (GCPolicy<T>::needsSweep(&e.mutableFront()))
  232. e.removeFront();
  233. }
  234. }
  235. // GCHashSet is movable
  236. GCHashSet(GCHashSet&& rhs) : Base(mozilla::Move(rhs)) {}
  237. void operator=(GCHashSet&& rhs) {
  238. MOZ_ASSERT(this != &rhs, "self-move assignment is prohibited");
  239. Base::operator=(mozilla::Move(rhs));
  240. }
  241. private:
  242. // GCHashSet is not copyable or assignable
  243. GCHashSet(const GCHashSet& hs) = delete;
  244. GCHashSet& operator=(const GCHashSet& hs) = delete;
  245. };
  246. } // namespace JS
  247. namespace js {
  248. template <typename Outer, typename... Args>
  249. class GCHashSetOperations
  250. {
  251. using Set = JS::GCHashSet<Args...>;
  252. using Lookup = typename Set::Lookup;
  253. const Set& set() const { return static_cast<const Outer*>(this)->get(); }
  254. public:
  255. using AddPtr = typename Set::AddPtr;
  256. using Entry = typename Set::Entry;
  257. using Ptr = typename Set::Ptr;
  258. using Range = typename Set::Range;
  259. bool initialized() const { return set().initialized(); }
  260. Ptr lookup(const Lookup& l) const { return set().lookup(l); }
  261. AddPtr lookupForAdd(const Lookup& l) const { return set().lookupForAdd(l); }
  262. Range all() const { return set().all(); }
  263. bool empty() const { return set().empty(); }
  264. uint32_t count() const { return set().count(); }
  265. size_t capacity() const { return set().capacity(); }
  266. bool has(const Lookup& l) const { return set().lookup(l).found(); }
  267. size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  268. return set().sizeOfExcludingThis(mallocSizeOf);
  269. }
  270. size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
  271. return mallocSizeOf(this) + set().sizeOfExcludingThis(mallocSizeOf);
  272. }
  273. };
  274. template <typename Outer, typename... Args>
  275. class MutableGCHashSetOperations
  276. : public GCHashSetOperations<Outer, Args...>
  277. {
  278. using Set = JS::GCHashSet<Args...>;
  279. using Lookup = typename Set::Lookup;
  280. Set& set() { return static_cast<Outer*>(this)->get(); }
  281. public:
  282. using AddPtr = typename Set::AddPtr;
  283. using Entry = typename Set::Entry;
  284. struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} };
  285. using Ptr = typename Set::Ptr;
  286. using Range = typename Set::Range;
  287. bool init(uint32_t len = 16) { return set().init(len); }
  288. void clear() { set().clear(); }
  289. void finish() { set().finish(); }
  290. void remove(Ptr p) { set().remove(p); }
  291. void remove(const Lookup& l) { set().remove(l); }
  292. template<typename TInput>
  293. bool add(AddPtr& p, TInput&& t) {
  294. return set().add(p, mozilla::Forward<TInput>(t));
  295. }
  296. template<typename TInput>
  297. bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) {
  298. return set().relookupOrAdd(p, l, mozilla::Forward<TInput>(t));
  299. }
  300. template<typename TInput>
  301. bool put(TInput&& t) {
  302. return set().put(mozilla::Forward<TInput>(t));
  303. }
  304. template<typename TInput>
  305. bool putNew(TInput&& t) {
  306. return set().putNew(mozilla::Forward<TInput>(t));
  307. }
  308. template<typename TInput>
  309. bool putNew(const Lookup& l, TInput&& t) {
  310. return set().putNew(l, mozilla::Forward<TInput>(t));
  311. }
  312. };
  313. template <typename T, typename HP, typename AP>
  314. class RootedBase<JS::GCHashSet<T, HP, AP>>
  315. : public MutableGCHashSetOperations<JS::Rooted<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
  316. {
  317. };
  318. template <typename T, typename HP, typename AP>
  319. class MutableHandleBase<JS::GCHashSet<T, HP, AP>>
  320. : public MutableGCHashSetOperations<JS::MutableHandle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
  321. {
  322. };
  323. template <typename T, typename HP, typename AP>
  324. class HandleBase<JS::GCHashSet<T, HP, AP>>
  325. : public GCHashSetOperations<JS::Handle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
  326. {
  327. };
  328. template <typename T, typename HP, typename AP>
  329. class WeakCacheBase<JS::GCHashSet<T, HP, AP>>
  330. : public MutableGCHashSetOperations<JS::WeakCache<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
  331. {
  332. };
  333. } /* namespace js */
  334. #endif /* GCHashTable_h */