diff -r 000000000000 -r 6474c204b198 js/src/jsweakcache.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/jsweakcache.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jsweakcache_h +#define jsweakcache_h + +#include "jscntxt.h" +#include "gc/Marking.h" +#include "js/HashTable.h" +#include "vm/Runtime.h" + +namespace js { + +// A WeakCache is used to map a key to a value similar to an HashMap except +// that its entries are garbage collected. An entry is kept as long as +// both the key and value are marked. +// +// No mark function is provided with this weak container. However, this weak +// container should take part in the sweep phase. +template , + class AllocPolicy = RuntimeAllocPolicy> +class WeakCache : public HashMap { + private: + typedef HashMap Base; + typedef typename Base::Range Range; + typedef typename Base::Enum Enum; + + public: + explicit WeakCache(JSRuntime *rt) : Base(rt) { } + explicit WeakCache(JSContext *cx) : Base(cx->runtime()) { } + + public: + // Sweep all entries which have unmarked key or value. + void sweep(FreeOp *fop) { + // Remove all entries whose keys/values remain unmarked. + for (Enum e(*this); !e.empty(); e.popFront()) { + // Checking IsMarked() may update the location of the Key (or Value). + // Pass in a stack local, then manually update the backing heap store. + Key k(e.front().key); + bool isKeyDying = gc::IsAboutToBeFinalized(&k); + + if (isKeyDying || gc::IsAboutToBeFinalized(e.front().value)) { + e.removeFront(); + } else { + // Potentially update the location of the Key. + // The Value had its heap addresses correctly passed to IsMarked(), + // and therefore has already been updated if necessary. + // e.rekeyFront(k); + } + } + +#if DEBUG + // Once we've swept, all remaining edges should stay within the + // known-live part of the graph. + for (Range r = Base::all(); !r.empty(); r.popFront()) { + Key k(r.front().key); + + JS_ASSERT(!gc::IsAboutToBeFinalized(&k)); + JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value)); + + // Assert that IsMarked() did not perform relocation. + JS_ASSERT(k == r.front().key); + } +#endif + } +}; + +// A WeakValueCache is similar to a WeakCache, except keys are never marked. +// This is useful for weak maps where the keys are primitive values such as uint32_t. +template , + class AllocPolicy = RuntimeAllocPolicy> +class WeakValueCache : public HashMap +{ + public: + typedef HashMap Base; + typedef typename Base::Range Range; + typedef typename Base::Enum Enum; + + explicit WeakValueCache(JSRuntime *rt) : Base(rt) { } + explicit WeakValueCache(JSContext *cx) : Base(cx->runtime()) { } + + public: + // Sweep all entries which have unmarked key or value. + void sweep(FreeOp *fop) { + // Remove all entries whose values remain unmarked. + for (Enum e(*this); !e.empty(); e.popFront()) { + if (gc::IsAboutToBeFinalized(e.front().value())) + e.removeFront(); + } + +#if DEBUG + // Once we've swept, all remaining edges should stay within the + // known-live part of the graph. + for (Range r = Base::all(); !r.empty(); r.popFront()) + JS_ASSERT(!gc::IsAboutToBeFinalized(r.front().value())); +#endif + } +}; + +} // namespace js + +#endif /* jsweakcache_h */