PageRenderTime 33ms CodeModel.GetById 15ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/js/src/jsweakmap.h

http://github.com/zpao/v8monkey
C Header | 350 lines | 183 code | 39 blank | 128 comment | 17 complexity | 968c38eff5daf3b9a6cce022fce110e9 MD5 | raw file
  1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 * vim: set ts=4 sw=4 et tw=99:
  3 *
  4 * ***** BEGIN LICENSE BLOCK *****
  5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6 *
  7 * The contents of this file are subject to the Mozilla Public License Version
  8 * 1.1 (the "License"); you may not use this file except in compliance with
  9 * the License. You may obtain a copy of the License at
 10 * http://www.mozilla.org/MPL/
 11 *
 12 * Software distributed under the License is distributed on an "AS IS" basis,
 13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 14 * for the specific language governing rights and limitations under the
 15 * License.
 16 *
 17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
 18 * May 28, 2008.
 19 *
 20 * The Initial Developer of the Original Code is
 21 *   Mozilla Foundation
 22 * Portions created by the Initial Developer are Copyright (C) 2009
 23 * the Initial Developer. All Rights Reserved.
 24 *
 25 * Contributor(s):
 26 *   Andreas Gal <gal@mozilla.com>
 27 *
 28 * Alternatively, the contents of this file may be used under the terms of
 29 * either of the GNU General Public License Version 2 or later (the "GPL"),
 30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 31 * in which case the provisions of the GPL or the LGPL are applicable instead
 32 * of those above. If you wish to allow use of your version of this file only
 33 * under the terms of either the GPL or the LGPL, and not to allow others to
 34 * use your version of this file under the terms of the MPL, indicate your
 35 * decision by deleting the provisions above and replace them with the notice
 36 * and other provisions required by the GPL or the LGPL. If you do not delete
 37 * the provisions above, a recipient may use your version of this file under
 38 * the terms of any one of the MPL, the GPL or the LGPL.
 39 *
 40 * ***** END LICENSE BLOCK ***** */
 41
 42#ifndef jsweakmap_h___
 43#define jsweakmap_h___
 44
 45#include "jsapi.h"
 46#include "jsfriendapi.h"
 47#include "jscntxt.h"
 48#include "jsobj.h"
 49#include "jsgcmark.h"
 50
 51#include "js/HashTable.h"
 52
 53namespace js {
 54
 55// A subclass template of js::HashMap whose keys and values may be garbage-collected. When
 56// a key is collected, the table entry disappears, dropping its reference to the value.
 57//
 58// More precisely:
 59//
 60//     A WeakMap entry is collected if and only if either the WeakMap or the entry's key
 61//     is collected. If an entry is not collected, it remains in the WeakMap and it has a
 62//     strong reference to the value.
 63//
 64// You must call this table's 'mark' method when the object of which it is a part is
 65// reached by the garbage collection tracer. Once a table is known to be live, the
 66// implementation takes care of the iterative marking needed for weak tables and removing
 67// table entries when collection is complete.
 68//
 69// You may provide your own MarkPolicy class to specify how keys and values are marked; a
 70// policy template provides default definitions for some common key/value type
 71// combinations.
 72//
 73// Details:
 74//
 75// The interface is as for a js::HashMap, with the following additions:
 76//
 77// - You must call the WeakMap's 'trace' member function when you discover that the map is
 78//   part of a live object. (You'll typically call this from the containing type's 'trace'
 79//   function.)
 80//
 81// - There is no AllocPolicy parameter; these are used with our garbage collector, so
 82//   RuntimeAllocPolicy is hard-wired.
 83//
 84// - Optional fourth and fifth parameters are the MarkPolicies for the key and value type.
 85//   A MarkPolicy has the constructor:
 86//
 87//     MarkPolicy(JSTracer *)
 88//
 89//   and the following member functions:
 90//
 91//     bool isMarked(const Type &x)
 92//        Return true if x has been marked as live by the garbage collector.
 93//
 94//     bool mark(const Type &x)
 95//        Return false if x is already marked. Otherwise, mark x and return true.
 96//
 97//   If omitted, the MarkPolicy parameter defaults to js::DefaultMarkPolicy<Type>,
 98//   a policy template with the obvious definitions for some typical
 99//   SpiderMonkey type combinations.
100
101// A policy template holding default marking algorithms for common type combinations. This
102// provides default types for WeakMap's MarkPolicy template parameter.
103template <class Type> class DefaultMarkPolicy;
104
105// A policy template holding default tracing algorithms for common type combinations. This
106// provides default types for WeakMap's TracePolicy template parameter.
107template <class Key, class Value> class DefaultTracePolicy;
108
109// The value for the next pointer for maps not in the map list.
110static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1);
111
112// Common base class for all WeakMap specializations. The collector uses this to call
113// their markIteratively and sweep methods.
114class WeakMapBase {
115  public:
116    WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { }
117    virtual ~WeakMapBase() { }
118
119    void trace(JSTracer *tracer) {
120        if (IS_GC_MARKING_TRACER(tracer)) {
121            // We don't do anything with a WeakMap at trace time. Rather, we wait until as
122            // many keys as possible have been marked, and add ourselves to the list of
123            // known-live WeakMaps to be scanned in the iterative marking phase, by
124            // markAllIteratively.
125            JS_ASSERT(!tracer->eagerlyTraceWeakMaps);
126
127            // Add ourselves to the list if we are not already in the list. We can already
128            // be in the list if the weak map is marked more than once due delayed marking.
129            if (next == WeakMapNotInList) {
130                JSRuntime *rt = tracer->context->runtime;
131                next = rt->gcWeakMapList;
132                rt->gcWeakMapList = this;
133            }
134        } else {
135            // If we're not actually doing garbage collection, the keys won't be marked
136            // nicely as needed by the true ephemeral marking algorithm --- custom tracers
137            // such as the cycle collector must use their own means for cycle detection.
138            // So here we do a conservative approximation: pretend all keys are live.
139            if (tracer->eagerlyTraceWeakMaps)
140                nonMarkingTrace(tracer);
141        }
142    }
143
144    // Garbage collector entry points.
145
146    // Check all weak maps that have been marked as live so far in this garbage
147    // collection, and mark the values of all entries that have become strong references
148    // to them. Return true if we marked any new values, indicating that we need to make
149    // another pass. In other words, mark my marked maps' marked members' mid-collection.
150    static bool markAllIteratively(JSTracer *tracer);
151
152    // Remove entries whose keys are dead from all weak maps marked as live in this
153    // garbage collection.
154    static void sweepAll(JSTracer *tracer);
155
156    // Trace all delayed weak map bindings. Used by the cycle collector.
157    static void traceAllMappings(WeakMapTracer *tracer);
158
159    // Remove everything from the live weak map list.
160    static void resetWeakMapList(JSRuntime *rt);
161
162  protected:
163    // Instance member functions called by the above. Instantiations of WeakMap override
164    // these with definitions appropriate for their Key and Value types.
165    virtual void nonMarkingTrace(JSTracer *tracer) = 0;
166    virtual bool markIteratively(JSTracer *tracer) = 0;
167    virtual void sweep(JSTracer *tracer) = 0;
168    virtual void traceMappings(WeakMapTracer *tracer) = 0;
169
170    // Object that this weak map is part of, if any.
171    JSObject *memberOf;
172
173  private:
174    // Link in a list of WeakMaps to mark iteratively and sweep in this garbage
175    // collection, headed by JSRuntime::gcWeakMapList. The last element of the list
176    // has NULL as its next. Maps not in the list have WeakMapNotInList as their
177    // next.  We must distinguish these cases to avoid creating infinite lists
178    // when a weak map gets traced twice due to delayed marking.
179    WeakMapBase *next;
180};
181
182template <class Key, class Value,
183          class HashPolicy = DefaultHasher<Key>,
184          class KeyMarkPolicy = DefaultMarkPolicy<Key>,
185          class ValueMarkPolicy = DefaultMarkPolicy<Value>,
186          class TracePolicy = DefaultTracePolicy<Key, Value> >
187class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, public WeakMapBase {
188  private:
189    typedef HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy> Base;
190    typedef typename Base::Enum Enum;
191
192  public:
193    typedef typename Base::Range Range;
194
195    explicit WeakMap(JSRuntime *rt, JSObject *memOf=NULL) : Base(rt), WeakMapBase(memOf) { }
196    explicit WeakMap(JSContext *cx, JSObject *memOf=NULL) : Base(cx), WeakMapBase(memOf) { }
197
198    // Use with caution, as result can be affected by garbage collection.
199    Range nondeterministicAll() {
200        return Base::all();
201    }
202
203  private:
204    void nonMarkingTrace(JSTracer *trc) {
205        ValueMarkPolicy vp(trc);
206        for (Range r = Base::all(); !r.empty(); r.popFront())
207            vp.mark(r.front().value);
208    }
209
210    bool markIteratively(JSTracer *trc) {
211        KeyMarkPolicy kp(trc);
212        ValueMarkPolicy vp(trc);
213        bool markedAny = false;
214        for (Range r = Base::all(); !r.empty(); r.popFront()) {
215            const Key &k = r.front().key;
216            const Value &v = r.front().value;
217            /* If the entry is live, ensure its key and value are marked. */
218            if (kp.isMarked(k)) {
219                markedAny |= vp.mark(v);
220            }
221            JS_ASSERT_IF(kp.isMarked(k), vp.isMarked(v));
222        }
223        return markedAny;
224    }
225
226    void sweep(JSTracer *trc) {
227        KeyMarkPolicy kp(trc);
228
229        /* Remove all entries whose keys remain unmarked. */
230        for (Enum e(*this); !e.empty(); e.popFront()) {
231            if (!kp.isMarked(e.front().key))
232                e.removeFront();
233        }
234
235#if DEBUG
236        ValueMarkPolicy vp(trc);
237        /*
238         * Once we've swept, all remaining edges should stay within the
239         * known-live part of the graph.
240         */
241        for (Range r = Base::all(); !r.empty(); r.popFront()) {
242            JS_ASSERT(kp.isMarked(r.front().key));
243            JS_ASSERT(vp.isMarked(r.front().value));
244        }
245#endif
246    }
247
248    // mapObj can be NULL, which means that the map is not part of a JSObject.
249    void traceMappings(WeakMapTracer *tracer) {
250        TracePolicy t(tracer);
251        for (Range r = Base::all(); !r.empty(); r.popFront())
252            t.traceMapping(memberOf, r.front().key, r.front().value);
253    }
254};
255
256template <>
257class DefaultMarkPolicy<HeapValue> {
258  private:
259    JSTracer *tracer;
260  public:
261    DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
262    bool isMarked(const HeapValue &x) {
263        if (x.isMarkable())
264            return !IsAboutToBeFinalized(x);
265        return true;
266    }
267    bool mark(const HeapValue &x) {
268        if (isMarked(x))
269            return false;
270        js::gc::MarkValue(tracer, x, "WeakMap entry");
271        return true;
272    }
273};
274
275template <>
276class DefaultMarkPolicy<HeapPtrObject> {
277  private:
278    JSTracer *tracer;
279  public:
280    DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
281    bool isMarked(const HeapPtrObject &x) {
282        return !IsAboutToBeFinalized(x);
283    }
284    bool mark(const HeapPtrObject &x) {
285        if (isMarked(x))
286            return false;
287        js::gc::MarkObject(tracer, x, "WeakMap entry");
288        return true;
289    }
290};
291
292template <>
293class DefaultMarkPolicy<HeapPtrScript> {
294  private:
295    JSTracer *tracer;
296  public:
297    DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
298    bool isMarked(const HeapPtrScript &x) {
299        return !IsAboutToBeFinalized(x);
300    }
301    bool mark(const HeapPtrScript &x) {
302        if (isMarked(x))
303            return false;
304        js::gc::MarkScript(tracer, x, "WeakMap entry");
305        return true;
306    }
307};
308
309// Default trace policies
310
311template <>
312class DefaultTracePolicy<HeapPtrObject, HeapValue> {
313  private:
314    WeakMapTracer *tracer;
315  public:
316    DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
317    void traceMapping(JSObject *m, const HeapPtr<JSObject> &k, HeapValue &v) {
318        if (v.isMarkable())
319            tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.toGCThing(), v.gcKind());
320    }
321};
322
323template <>
324class DefaultTracePolicy<HeapPtrObject, HeapPtrObject> {
325  private:
326    WeakMapTracer *tracer;
327  public:
328    DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
329    void traceMapping(JSObject *m, const HeapPtrObject &k, const HeapPtrObject &v) {
330        tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.get(), JSTRACE_OBJECT);
331    }
332};
333
334template <>
335class DefaultTracePolicy<HeapPtrScript, HeapPtrObject> {
336  private:
337    WeakMapTracer *tracer;
338  public:
339    DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
340    void traceMapping(JSObject *m, const HeapPtrScript &k, const HeapPtrObject &v) {
341        tracer->callback(tracer, m, k.get(), JSTRACE_SCRIPT, v.get(), JSTRACE_OBJECT);
342    }
343};
344
345}
346
347extern JSObject *
348js_InitWeakMapClass(JSContext *cx, JSObject *obj);
349
350#endif