1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsweakcache.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,107 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jsweakcache_h 1.11 +#define jsweakcache_h 1.12 + 1.13 +#include "jscntxt.h" 1.14 +#include "gc/Marking.h" 1.15 +#include "js/HashTable.h" 1.16 +#include "vm/Runtime.h" 1.17 + 1.18 +namespace js { 1.19 + 1.20 +// A WeakCache is used to map a key to a value similar to an HashMap except 1.21 +// that its entries are garbage collected. An entry is kept as long as 1.22 +// both the key and value are marked. 1.23 +// 1.24 +// No mark function is provided with this weak container. However, this weak 1.25 +// container should take part in the sweep phase. 1.26 +template <class Key, class Value, 1.27 + class HashPolicy = DefaultHasher<Key>, 1.28 + class AllocPolicy = RuntimeAllocPolicy> 1.29 +class WeakCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> { 1.30 + private: 1.31 + typedef HashMap<Key, Value, HashPolicy, AllocPolicy> Base; 1.32 + typedef typename Base::Range Range; 1.33 + typedef typename Base::Enum Enum; 1.34 + 1.35 + public: 1.36 + explicit WeakCache(JSRuntime *rt) : Base(rt) { } 1.37 + explicit WeakCache(JSContext *cx) : Base(cx->runtime()) { } 1.38 + 1.39 + public: 1.40 + // Sweep all entries which have unmarked key or value. 1.41 + void sweep(FreeOp *fop) { 1.42 + // Remove all entries whose keys/values remain unmarked. 1.43 + for (Enum e(*this); !e.empty(); e.popFront()) { 1.44 + // Checking IsMarked() may update the location of the Key (or Value). 1.45 + // Pass in a stack local, then manually update the backing heap store. 1.46 + Key k(e.front().key); 1.47 + bool isKeyDying = gc::IsAboutToBeFinalized(&k); 1.48 + 1.49 + if (isKeyDying || gc::IsAboutToBeFinalized(e.front().value)) { 1.50 + e.removeFront(); 1.51 + } else { 1.52 + // Potentially update the location of the Key. 1.53 + // The Value had its heap addresses correctly passed to IsMarked(), 1.54 + // and therefore has already been updated if necessary. 1.55 + // e.rekeyFront(k); 1.56 + } 1.57 + } 1.58 + 1.59 +#if DEBUG 1.60 + // Once we've swept, all remaining edges should stay within the 1.61 + // known-live part of the graph. 1.62 + for (Range r = Base::all(); !r.empty(); r.popFront()) { 1.63 + Key k(r.front().key); 1.64 + 1.65 + JS_ASSERT(!gc::IsAboutToBeFinalized(&k)); 1.66 + JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value)); 1.67 + 1.68 + // Assert that IsMarked() did not perform relocation. 1.69 + JS_ASSERT(k == r.front().key); 1.70 + } 1.71 +#endif 1.72 + } 1.73 +}; 1.74 + 1.75 +// A WeakValueCache is similar to a WeakCache, except keys are never marked. 1.76 +// This is useful for weak maps where the keys are primitive values such as uint32_t. 1.77 +template <class Key, class Value, 1.78 + class HashPolicy = DefaultHasher<Key>, 1.79 + class AllocPolicy = RuntimeAllocPolicy> 1.80 +class WeakValueCache : public HashMap<Key, Value, HashPolicy, AllocPolicy> 1.81 +{ 1.82 + public: 1.83 + typedef HashMap<Key, Value, HashPolicy, AllocPolicy> Base; 1.84 + typedef typename Base::Range Range; 1.85 + typedef typename Base::Enum Enum; 1.86 + 1.87 + explicit WeakValueCache(JSRuntime *rt) : Base(rt) { } 1.88 + explicit WeakValueCache(JSContext *cx) : Base(cx->runtime()) { } 1.89 + 1.90 + public: 1.91 + // Sweep all entries which have unmarked key or value. 1.92 + void sweep(FreeOp *fop) { 1.93 + // Remove all entries whose values remain unmarked. 1.94 + for (Enum e(*this); !e.empty(); e.popFront()) { 1.95 + if (gc::IsAboutToBeFinalized(e.front().value())) 1.96 + e.removeFront(); 1.97 + } 1.98 + 1.99 +#if DEBUG 1.100 + // Once we've swept, all remaining edges should stay within the 1.101 + // known-live part of the graph. 1.102 + for (Range r = Base::all(); !r.empty(); r.popFront()) 1.103 + JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value())); 1.104 +#endif 1.105 + } 1.106 +}; 1.107 + 1.108 +} // namespace js 1.109 + 1.110 +#endif /* jsweakcache_h */