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