LCOV - app.info - js/src/jsweakmap.h

LCOV - code coverage report
| Current view: | directory - js/src - jsweakmap.h (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 69 | 49 | 71.0 %
| Date: | 2012-04-07 | Functions: | 38 | 26 | 68.4 %

           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                 :
          53                 : namespace 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(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                 : // The value for the next pointer for maps not in the map list.
         102                 : static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1);
         103                 :
         104                 : typedef Vector<WeakMapBase *, 0, SystemAllocPolicy> WeakMapVector;
         105                 :
         106                 : // Common base class for all WeakMap specializations. The collector uses this to call
         107                 : // their markIteratively and sweep methods.
         108                 : class WeakMapBase {
         109                 :   public:
         110           12831 :     WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { }
         111           12831 :     virtual ~WeakMapBase() { }
         112                 :
         113           20490 :     void trace(JSTracer *tracer) {
         114           20490 :         if (IS_GC_MARKING_TRACER(tracer)) {
         115                 :             // We don't do anything with a WeakMap at trace time. Rather, we wait until as
         116                 :             // many keys as possible have been marked, and add ourselves to the list of
         117                 :             // known-live WeakMaps to be scanned in the iterative marking phase, by
         118                 :             // markAllIteratively.
         119            8730 :             JS_ASSERT(!tracer->eagerlyTraceWeakMaps);
         120                 :
         121                 :             // Add ourselves to the list if we are not already in the list. We can already
         122                 :             // be in the list if the weak map is marked more than once due delayed marking.
         123            8730 :             if (next == WeakMapNotInList) {
         124            8730 :                 JSRuntime *rt = tracer->runtime;
         125            8730 :                 next = rt->gcWeakMapList;
         126            8730 :                 rt->gcWeakMapList = this;
         127            8730 :             }
         128                 :         } else {
         129                 :             // If we're not actually doing garbage collection, the keys won't be marked
         130                 :             // nicely as needed by the true ephemeral marking algorithm --- custom tracers
         131                 :             // such as the cycle collector must use their own means for cycle detection.
         132                 :             // So here we do a conservative approximation: pretend all keys are live.
         133           11760 :             if (tracer->eagerlyTraceWeakMaps)
         134           11760 :                 nonMarkingTrace(tracer);
         135                 :         }
         136           20490 :     }
         137                 :
         138                 :     // Garbage collector entry points.
         139                 :
         140                 :     // Check all weak maps that have been marked as live so far in this garbage
         141                 :     // collection, and mark the values of all entries that have become strong references
         142                 :     // to them. Return true if we marked any new values, indicating that we need to make
         143                 :     // another pass. In other words, mark my marked maps' marked members' mid-collection.
         144                 :     static bool markAllIteratively(JSTracer *tracer);
         145                 :
         146                 :     // Remove entries whose keys are dead from all weak maps marked as live in this
         147                 :     // garbage collection.
         148                 :     static void sweepAll(JSTracer *tracer);
         149                 :
         150                 :     // Trace all delayed weak map bindings. Used by the cycle collector.
         151                 :     static void traceAllMappings(WeakMapTracer *tracer);
         152                 :
         153              54 :     void check() { JS_ASSERT(next == WeakMapNotInList); }
         154                 :
         155                 :     // Remove everything from the live weak map list.
         156                 :     static void resetWeakMapList(JSRuntime *rt);
         157                 :
         158                 :     // Save and restore the live weak map list to a vector.
         159                 :     static bool saveWeakMapList(JSRuntime *rt, WeakMapVector &vector);
         160                 :     static void restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector);
         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                 :
         182                 : template <class Key, class Value,
         183                 :           class HashPolicy = DefaultHasher<Key> >
         184           12831 : class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, public WeakMapBase {
         185                 :   private:
         186                 :     typedef HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy> Base;
         187                 :     typedef typename Base::Enum Enum;
         188                 :
         189                 :   public:
         190                 :     typedef typename Base::Range Range;
         191                 :
         192                 :     explicit WeakMap(JSRuntime *rt, JSObject *memOf=NULL) : Base(rt), WeakMapBase(memOf) { }
         193           12831 :     explicit WeakMap(JSContext *cx, JSObject *memOf=NULL) : Base(cx), WeakMapBase(memOf) { }
         194                 :
         195                 :     /* Use with caution, as result can be affected by garbage collection. */
         196               0 :     Range nondeterministicAll() {
         197               0 :         return Base::all();
         198                 :     }
         199                 :
         200                 :   private:
         201             900 :     bool IsMarked(const HeapValue &x) {
         202             900 :         if (x.isMarkable())
         203               0 :             return !IsAboutToBeFinalized(x);
         204             900 :         return true;
         205                 :     }
         206           45452 :     bool IsMarked(const HeapPtrObject &x) {
         207           45452 :         return !IsAboutToBeFinalized(x);
         208                 :     }
         209            7322 :     bool IsMarked(const HeapPtrScript&x) {
         210            7322 :         return !IsAboutToBeFinalized(x);
         211                 :     }
         212                 :
         213             360 :     bool Mark(JSTracer *trc, HeapValue *x) {
         214             360 :         if (IsMarked(*x))
         215             360 :             return false;
         216               0 :         js::gc::MarkValue(trc, x, "WeakMap entry value");
         217               0 :         return true;
         218                 :     }
         219            9861 :     bool Mark(JSTracer *trc, HeapPtrObject *x) {
         220            9861 :         if (IsMarked(*x))
         221            8320 :             return false;
         222            1541 :         js::gc::MarkObject(trc, x, "WeakMap entry value");
         223            1541 :         return true;
         224                 :     }
         225                 :     bool Mark(JSTracer *trc, HeapPtrScript *x) {
         226                 :         if (IsMarked(*x))
         227                 :             return false;
         228                 :         js::gc::MarkScript(trc, x, "WeakMap entry value");
         229                 :         return true;
         230                 :     }
         231                 :
         232           11760 :     void nonMarkingTrace(JSTracer *trc) {
         233           11760 :         for (Range r = Base::all(); !r.empty(); r.popFront())
         234               0 :             Mark(trc, &r.front().value);
         235           11760 :     }
         236                 :
         237           19782 :     bool markIteratively(JSTracer *trc) {
         238           19782 :         bool markedAny = false;
         239           30442 :         for (Range r = Base::all(); !r.empty(); r.popFront()) {
         240                 :             /* If the entry is live, ensure its key and value are marked. */
         241           10660 :             if (IsMarked(r.front().key) && Mark(trc, &r.front().value))
         242            1541 :                 markedAny = true;
         243           10660 :             JS_ASSERT_IF(IsMarked(r.front().key), IsMarked(r.front().value));
         244                 :         }
         245           19782 :         return markedAny;
         246                 :     }
         247                 :
         248            8730 :     void sweep(JSTracer *trc) {
         249                 :         /* Remove all entries whose keys remain unmarked. */
         250           12784 :         for (Enum e(*this); !e.empty(); e.popFront()) {
         251            4054 :             if (!IsMarked(e.front().key))
         252             125 :                 e.removeFront();
         253                 :         }
         254                 :
         255                 : #if DEBUG
         256                 :         /*
         257                 :          * Once we've swept, all remaining edges should stay within the
         258                 :          * known-live part of the graph.
         259                 :          */
         260           12659 :         for (Range r = Base::all(); !r.empty(); r.popFront()) {
         261            3929 :             JS_ASSERT(IsMarked(r.front().key));
         262            3929 :             JS_ASSERT(IsMarked(r.front().value));
         263                 :         }
         264                 : #endif
         265            8730 :     }
         266                 :
         267               0 :     void CallTracer(WeakMapTracer *trc, const HeapPtrObject &k, const HeapValue &v) {
         268               0 :         if (v.isMarkable())
         269               0 :             trc->callback(trc, memberOf, k.get(), JSTRACE_OBJECT, v.toGCThing(), v.gcKind());
         270               0 :     }
         271               0 :     void CallTracer(WeakMapTracer *trc, const HeapPtrObject &k, const HeapPtrObject &v) {
         272               0 :         trc->callback(trc, memberOf, k.get(), JSTRACE_OBJECT, v.get(), JSTRACE_OBJECT);
         273               0 :     }
         274               0 :     void CallTracer(WeakMapTracer *trc, const HeapPtrScript &k, const HeapPtrObject &v) {
         275               0 :         trc->callback(trc, memberOf, k.get(), JSTRACE_SCRIPT, v.get(), JSTRACE_OBJECT);
         276               0 :     }
         277                 :
         278                 :     /* mapObj can be NULL, which means that the map is not part of a JSObject. */
         279               0 :     void traceMappings(WeakMapTracer *tracer) {
         280               0 :         for (Range r = Base::all(); !r.empty(); r.popFront())
         281               0 :             CallTracer(tracer, r.front().key, r.front().value);
         282               0 :     }
         283                 : };
         284                 :
         285                 : } /* namespace js */
         286                 :
         287                 : extern JSObject *
         288                 : js_InitWeakMapClass(JSContext *cx, JSObject *obj);
         289                 :
         290                 : #endif

Generated by: LCOV version 1.7