LCOV - code coverage report
Current view: directory - js/src - jsweakmap.h (source / functions) Found Hit Coverage
Test: app.info Lines: 83 64 77.1 %
Date: 2012-06-02 Functions: 41 28 68.3 %

       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                 : // A policy template holding default marking algorithms for common type combinations. This
     102                 : // provides default types for WeakMap's MarkPolicy template parameter.
     103                 : template <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.
     107                 : template <class Key, class Value> class DefaultTracePolicy;
     108                 : 
     109                 : // The value for the next pointer for maps not in the map list.
     110                 : static WeakMapBase * const WeakMapNotInList = reinterpret_cast<WeakMapBase *>(1);
     111                 : 
     112                 : typedef Vector<WeakMapBase *, 0, SystemAllocPolicy> WeakMapVector;
     113                 : 
     114                 : // Common base class for all WeakMap specializations. The collector uses this to call
     115                 : // their markIteratively and sweep methods.
     116                 : class WeakMapBase {
     117                 :   public:
     118           12764 :     WeakMapBase(JSObject *memOf) : memberOf(memOf), next(WeakMapNotInList) { }
     119           12764 :     virtual ~WeakMapBase() { }
     120                 : 
     121           20488 :     void trace(JSTracer *tracer) {
     122           20488 :         if (IS_GC_MARKING_TRACER(tracer)) {
     123                 :             // We don't do anything with a WeakMap at trace time. Rather, we wait until as
     124                 :             // many keys as possible have been marked, and add ourselves to the list of
     125                 :             // known-live WeakMaps to be scanned in the iterative marking phase, by
     126                 :             // markAllIteratively.
     127            8728 :             JS_ASSERT(!tracer->eagerlyTraceWeakMaps);
     128                 : 
     129                 :             // Add ourselves to the list if we are not already in the list. We can already
     130                 :             // be in the list if the weak map is marked more than once due delayed marking.
     131            8728 :             if (next == WeakMapNotInList) {
     132            8728 :                 JSRuntime *rt = tracer->runtime;
     133            8728 :                 next = rt->gcWeakMapList;
     134            8728 :                 rt->gcWeakMapList = this;
     135            8728 :             }
     136                 :         } else {
     137                 :             // If we're not actually doing garbage collection, the keys won't be marked
     138                 :             // nicely as needed by the true ephemeral marking algorithm --- custom tracers
     139                 :             // such as the cycle collector must use their own means for cycle detection.
     140                 :             // So here we do a conservative approximation: pretend all keys are live.
     141           11760 :             if (tracer->eagerlyTraceWeakMaps)
     142           11760 :                 nonMarkingTrace(tracer);
     143                 :         }
     144           20488 :     }
     145                 : 
     146                 :     // Garbage collector entry points.
     147                 : 
     148                 :     // Check all weak maps that have been marked as live so far in this garbage
     149                 :     // collection, and mark the values of all entries that have become strong references
     150                 :     // to them. Return true if we marked any new values, indicating that we need to make
     151                 :     // another pass. In other words, mark my marked maps' marked members' mid-collection.
     152                 :     static bool markAllIteratively(JSTracer *tracer);
     153                 : 
     154                 :     // Remove entries whose keys are dead from all weak maps marked as live in this
     155                 :     // garbage collection.
     156                 :     static void sweepAll(JSTracer *tracer);
     157                 : 
     158                 :     // Trace all delayed weak map bindings. Used by the cycle collector.
     159                 :     static void traceAllMappings(WeakMapTracer *tracer);
     160                 : 
     161             122 :     void check() { JS_ASSERT(next == WeakMapNotInList); }
     162                 : 
     163                 :     // Remove everything from the live weak map list.
     164                 :     static void resetWeakMapList(JSRuntime *rt);
     165                 : 
     166                 :     // Save and restore the live weak map list to a vector.
     167                 :     static bool saveWeakMapList(JSRuntime *rt, WeakMapVector &vector);
     168                 :     static void restoreWeakMapList(JSRuntime *rt, WeakMapVector &vector);
     169                 : 
     170                 :   protected:
     171                 :     // Instance member functions called by the above. Instantiations of WeakMap override
     172                 :     // these with definitions appropriate for their Key and Value types.
     173                 :     virtual void nonMarkingTrace(JSTracer *tracer) = 0;
     174                 :     virtual bool markIteratively(JSTracer *tracer) = 0;
     175                 :     virtual void sweep(JSTracer *tracer) = 0;
     176                 :     virtual void traceMappings(WeakMapTracer *tracer) = 0;
     177                 : 
     178                 :     // Object that this weak map is part of, if any.
     179                 :     JSObject *memberOf;
     180                 : 
     181                 :   private:
     182                 :     // Link in a list of WeakMaps to mark iteratively and sweep in this garbage
     183                 :     // collection, headed by JSRuntime::gcWeakMapList. The last element of the list
     184                 :     // has NULL as its next. Maps not in the list have WeakMapNotInList as their
     185                 :     // next.  We must distinguish these cases to avoid creating infinite lists
     186                 :     // when a weak map gets traced twice due to delayed marking.
     187                 :     WeakMapBase *next;
     188                 : };
     189                 : 
     190                 : template <class Key, class Value,
     191                 :           class HashPolicy = DefaultHasher<Key>,
     192                 :           class KeyMarkPolicy = DefaultMarkPolicy<Key>,
     193                 :           class ValueMarkPolicy = DefaultMarkPolicy<Value>,
     194                 :           class TracePolicy = DefaultTracePolicy<Key, Value> >
     195           12764 : class WeakMap : public HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy>, public WeakMapBase {
     196                 :   private:
     197                 :     typedef HashMap<Key, Value, HashPolicy, RuntimeAllocPolicy> Base;
     198                 :     typedef typename Base::Enum Enum;
     199                 : 
     200                 :   public:
     201                 :     typedef typename Base::Range Range;
     202                 : 
     203                 :     explicit WeakMap(JSRuntime *rt, JSObject *memOf=NULL) : Base(rt), WeakMapBase(memOf) { }
     204           12764 :     explicit WeakMap(JSContext *cx, JSObject *memOf=NULL) : Base(cx), WeakMapBase(memOf) { }
     205                 : 
     206                 :     // Use with caution, as result can be affected by garbage collection.
     207               0 :     Range nondeterministicAll() {
     208               0 :         return Base::all();
     209                 :     }
     210                 : 
     211                 :   private:
     212           11760 :     void nonMarkingTrace(JSTracer *trc) {
     213           11760 :         ValueMarkPolicy vp(trc);
     214           11760 :         for (Range r = Base::all(); !r.empty(); r.popFront())
     215               0 :             vp.mark(&r.front().value);
     216           11760 :     }
     217                 : 
     218           19772 :     bool markIteratively(JSTracer *trc) {
     219           19772 :         KeyMarkPolicy kp(trc);
     220           19772 :         ValueMarkPolicy vp(trc);
     221           19772 :         bool markedAny = false;
     222           30431 :         for (Range r = Base::all(); !r.empty(); r.popFront()) {
     223           10659 :             const Key &k = r.front().key;
     224           10659 :             Value &v = r.front().value;
     225                 :             /* If the entry is live, ensure its key and value are marked. */
     226           10659 :             if (kp.isMarked(k)) {
     227           10216 :                 markedAny |= vp.mark(&v);
     228                 :             }
     229           10659 :             JS_ASSERT_IF(kp.isMarked(k), vp.isMarked(v));
     230                 :         }
     231           19772 :         return markedAny;
     232                 :     }
     233                 : 
     234            8728 :     void sweep(JSTracer *trc) {
     235            8728 :         KeyMarkPolicy kp(trc);
     236                 : 
     237                 :         /* Remove all entries whose keys remain unmarked. */
     238           12784 :         for (Enum e(*this); !e.empty(); e.popFront()) {
     239            4056 :             if (!kp.isMarked(e.front().key))
     240             127 :                 e.removeFront();
     241                 :         }
     242                 : 
     243                 : #if DEBUG
     244            8728 :         ValueMarkPolicy vp(trc);
     245                 :         /*
     246                 :          * Once we've swept, all remaining edges should stay within the
     247                 :          * known-live part of the graph.
     248                 :          */
     249           12657 :         for (Range r = Base::all(); !r.empty(); r.popFront()) {
     250            3929 :             JS_ASSERT(kp.isMarked(r.front().key));
     251            3929 :             JS_ASSERT(vp.isMarked(r.front().value));
     252                 :         }
     253                 : #endif
     254            8728 :     }
     255                 : 
     256                 :     // mapObj can be NULL, which means that the map is not part of a JSObject.
     257               1 :     void traceMappings(WeakMapTracer *tracer) {
     258               1 :         TracePolicy t(tracer);
     259               1 :         for (Range r = Base::all(); !r.empty(); r.popFront())
     260               0 :             t.traceMapping(memberOf, r.front().key, r.front().value);
     261               1 :     }
     262                 : };
     263                 : 
     264                 : template <>
     265                 : class DefaultMarkPolicy<HeapValue> {
     266                 :   private:
     267                 :     JSTracer *tracer;
     268                 :   public:
     269              84 :     DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
     270             900 :     bool isMarked(const HeapValue &x) {
     271             900 :         if (x.isMarkable())
     272               0 :             return !IsAboutToBeFinalized(x);
     273             900 :         return true;
     274                 :     }
     275             360 :     bool mark(HeapValue *x) {
     276             360 :         if (isMarked(*x))
     277             360 :             return false;
     278               0 :         js::gc::MarkValue(tracer, x, "WeakMap entry");
     279               0 :         return true;
     280                 :     }
     281                 : };
     282                 : 
     283                 : template <>
     284                 : class DefaultMarkPolicy<HeapPtrObject> {
     285                 :   private:
     286                 :     JSTracer *tracer;
     287                 :   public:
     288           59204 :     DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
     289           45454 :     bool isMarked(const HeapPtrObject &x) {
     290           45454 :         return !IsAboutToBeFinalized(x);
     291                 :     }
     292            9856 :     bool mark(HeapPtrObject *x) {
     293            9856 :         if (isMarked(*x))
     294            8293 :             return false;
     295            1563 :         js::gc::MarkObject(tracer, x, "WeakMap entry");
     296            1563 :         return true;
     297                 :     }
     298                 : };
     299                 : 
     300                 : template <>
     301                 : class DefaultMarkPolicy<HeapPtrScript> {
     302                 :   private:
     303                 :     JSTracer *tracer;
     304                 :   public:
     305            9472 :     DefaultMarkPolicy(JSTracer *t) : tracer(t) { }
     306            7310 :     bool isMarked(const HeapPtrScript &x) {
     307            7310 :         return !IsAboutToBeFinalized(x);
     308                 :     }
     309                 :     bool mark(HeapPtrScript *x) {
     310                 :         if (isMarked(*x))
     311                 :             return false;
     312                 :         js::gc::MarkScript(tracer, x, "WeakMap entry");
     313                 :         return true;
     314                 :     }
     315                 : };
     316                 : 
     317                 : // Default trace policies
     318                 : 
     319                 : template <>
     320                 : class DefaultTracePolicy<HeapPtrObject, HeapValue> {
     321                 :   private:
     322                 :     WeakMapTracer *tracer;
     323                 :   public:
     324               1 :     DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
     325               0 :     void traceMapping(JSObject *m, const HeapPtr<JSObject> &k, HeapValue &v) {
     326               0 :         if (v.isMarkable())
     327               0 :             tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.toGCThing(), v.gcKind());
     328               0 :     }
     329                 : };
     330                 : 
     331                 : template <>
     332                 : class DefaultTracePolicy<HeapPtrObject, HeapPtrObject> {
     333                 :   private:
     334                 :     WeakMapTracer *tracer;
     335                 :   public:
     336               0 :     DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
     337               0 :     void traceMapping(JSObject *m, const HeapPtrObject &k, const HeapPtrObject &v) {
     338               0 :         tracer->callback(tracer, m, k.get(), JSTRACE_OBJECT, v.get(), JSTRACE_OBJECT);
     339               0 :     }
     340                 : };
     341                 : 
     342                 : template <>
     343                 : class DefaultTracePolicy<HeapPtrScript, HeapPtrObject> {
     344                 :   private:
     345                 :     WeakMapTracer *tracer;
     346                 :   public:
     347               0 :     DefaultTracePolicy(WeakMapTracer *t) : tracer(t) { }
     348               0 :     void traceMapping(JSObject *m, const HeapPtrScript &k, const HeapPtrObject &v) {
     349               0 :         tracer->callback(tracer, m, k.get(), JSTRACE_SCRIPT, v.get(), JSTRACE_OBJECT);
     350               0 :     }
     351                 : };
     352                 : 
     353                 : }
     354                 : 
     355                 : extern JSObject *
     356                 : js_InitWeakMapClass(JSContext *cx, JSObject *obj);
     357                 : 
     358                 : #endif

Generated by: LCOV version 1.7