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 jsweakcache_h 8 #define jsweakcache_h 9 10 #include "jscntxt.h" 11 #include "gc/Marking.h" 12 #include "js/HashTable.h" 13 #include "vm/Runtime.h" 14 15 namespace js { 16 17 // A WeakCache is used to map a key to a value similar to an HashMap except 18 // that its entries are garbage collected. An entry is kept as long as 19 // both the key and value are marked. 20 // 21 // No mark function is provided with this weak container. However, this weak 22 // container should take part in the sweep phase. 23 template <class Key, class Value, 24 class HashPolicy = DefaultHasher<Key>, 25 class AllocPolicy = RuntimeAllocPolicy> 26 class WeakCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> { 27 private: 28 typedef HashMap<Key, Value, HashPolicy, AllocPolicy> Base; 29 typedef typename Base::Range Range; 30 typedef typename Base::Enum Enum; 31 32 public: WeakCache(JSRuntime * rt)33 explicit WeakCache(JSRuntime* rt) : Base(rt) { } WeakCache(JSContext * cx)34 explicit WeakCache(JSContext* cx) : Base(cx->runtime()) { } 35 36 public: 37 // Sweep all entries which have unmarked key or value. sweep(FreeOp * fop)38 void sweep(FreeOp* fop) { 39 // Remove all entries whose keys/values remain unmarked. 40 for (Enum e(*this); !e.empty(); e.popFront()) { 41 // IsAboutToBeFinalized() may update the location of the Key (or Value). 42 // Pass in a stack local, then manually update the backing heap store. 43 Key key(e.front().key); 44 MOZ_ASSERT(key); 45 MOZ_ASSERT(e.front().value()); 46 if (gc::IsAboutToBeFinalized(&key) || gc::IsAboutToBeFinalized(e.front().value)) 47 e.removeFront(); 48 else if (key != e.front().key) 49 e.rekeyFront(key); 50 } 51 52 #ifdef DEBUG 53 // Once we've swept, all remaining edges should stay within the 54 // known-live part of the graph. 55 for (Range r = Base::all(); !r.empty(); r.popFront()) { 56 Key key(r.front().key); 57 Value value(r.front().value); 58 MOZ_ASSERT(key); 59 MOZ_ASSERT(value); 60 MOZ_ASSERT(!gc::IsAboutToBeFinalized(&key)); 61 MOZ_ASSERT(!gc::IsAboutToBeFinalized(&value)); 62 CheckGCThingAfterMovingGC(key); 63 CheckGCThingAfterMovingGC(value); 64 auto ptr = this->lookup(key); 65 MOZ_ASSERT(ptr.found() && &*ptr == &r.front()); 66 } 67 #endif 68 } 69 }; 70 71 // A WeakValueCache is similar to a WeakCache, except keys are never marked. 72 // This is useful for weak maps where the keys are primitive values such as uint32_t. 73 template <class Key, class Value, 74 class HashPolicy = DefaultHasher<Key>, 75 class AllocPolicy = RuntimeAllocPolicy> 76 class WeakValueCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> 77 { 78 public: 79 typedef HashMap<Key, Value, HashPolicy, AllocPolicy> Base; 80 typedef typename Base::Range Range; 81 typedef typename Base::Enum Enum; 82 WeakValueCache(JSRuntime * rt)83 explicit WeakValueCache(JSRuntime* rt) : Base(rt) { } WeakValueCache(JSContext * cx)84 explicit WeakValueCache(JSContext* cx) : Base(cx->runtime()) { } 85 86 public: 87 // Sweep all entries which have unmarked key or value. sweep(FreeOp * fop)88 void sweep(FreeOp* fop) { 89 // Remove all entries whose values remain unmarked. 90 for (Enum e(*this); !e.empty(); e.popFront()) { 91 MOZ_ASSERT(e.front().value()); 92 if (gc::IsAboutToBeFinalized(&e.front().value())) 93 e.removeFront(); 94 } 95 96 #ifdef DEBUG 97 // Once we've swept, all remaining edges should stay within the 98 // known-live part of the graph. 99 for (Range r = Base::all(); !r.empty(); r.popFront()) { 100 Value value(r.front().value()); 101 MOZ_ASSERT(value); 102 MOZ_ASSERT(!gc::IsAboutToBeFinalized(&value)); 103 CheckGCThingAfterMovingGC(value); 104 auto ptr = this->lookup(r.front().key()); 105 MOZ_ASSERT(ptr.found() && &*ptr == &r.front()); 106 } 107 #endif 108 } 109 }; 110 111 } // namespace js 112 113 #endif /* jsweakcache_h */ 114