LCOV - code coverage report
Current view: directory - js/src/frontend - ParseMaps.h (source / functions) Found Hit Coverage
Test: app.info Lines: 131 121 92.4 %
Date: 2012-06-02 Functions: 48 47 97.9 %

       1                 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99 ft=cpp:
       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 SpiderMonkey JavaScript engine.
      18                 :  *
      19                 :  * The Initial Developer of the Original Code is
      20                 :  * Mozilla Corporation.
      21                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      22                 :  * the Initial Developer. All Rights Reserved.
      23                 :  *
      24                 :  * Contributor(s):
      25                 :  *   Chris Leary <cdleary@mozilla.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : 
      41                 : #ifndef ParseMaps_h__
      42                 : #define ParseMaps_h__
      43                 : 
      44                 : #include "mozilla/Attributes.h"
      45                 : 
      46                 : #include "ds/InlineMap.h"
      47                 : #include "js/HashTable.h"
      48                 : #include "js/Vector.h"
      49                 : 
      50                 : namespace js {
      51                 : 
      52                 : struct Definition;
      53                 : 
      54                 : /*
      55                 :  * A pool that permits the reuse of the backing storage for the defn, index, or
      56                 :  * defn-or-header (multi) maps.
      57                 :  *
      58                 :  * The pool owns all the maps that are given out, and is responsible for
      59                 :  * relinquishing all resources when |purgeAll| is triggered.
      60                 :  */
      61                 : class ParseMapPool
      62                 : {
      63                 :     typedef Vector<void *, 32, SystemAllocPolicy> RecyclableMaps;
      64                 : 
      65                 :     RecyclableMaps      all;
      66                 :     RecyclableMaps      recyclable;
      67                 :     JSContext           *cx;
      68                 : 
      69                 :     void checkInvariants();
      70                 : 
      71         3435852 :     void recycle(void *map) {
      72         3435852 :         JS_ASSERT(map);
      73                 : #ifdef DEBUG
      74         3435852 :         bool ok = false;
      75                 :         /* Make sure the map is in |all| but not already in |recyclable|. */
      76        73271492 :         for (void **it = all.begin(), **end = all.end(); it != end; ++it) {
      77        73271492 :             if (*it == map) {
      78         3435852 :                 ok = true;
      79         3435852 :                 break;
      80                 :             }
      81                 :         }
      82         3435852 :         JS_ASSERT(ok);
      83       137514019 :         for (void **it = recyclable.begin(), **end = recyclable.end(); it != end; ++it)
      84       134078167 :             JS_ASSERT(*it != map);
      85                 : #endif
      86         3435852 :         JS_ASSERT(recyclable.length() < all.length());
      87         3435852 :         recyclable.infallibleAppend(map); /* Reserved in allocateFresh. */
      88         3435852 :     }
      89                 : 
      90                 :     void *allocateFresh();
      91                 :     void *allocate();
      92                 : 
      93                 :     /* Arbitrary atom map type, that has keys and values of the same kind. */
      94                 :     typedef AtomIndexMap AtomMapT;
      95                 : 
      96         3436438 :     static AtomMapT *asAtomMap(void *ptr) {
      97         3436438 :         return reinterpret_cast<AtomMapT *>(ptr);
      98                 :     }
      99                 : 
     100                 :   public:
     101           22498 :     explicit ParseMapPool(JSContext *cx) : cx(cx) {}
     102                 : 
     103           44996 :     ~ParseMapPool() {
     104           22498 :         purgeAll();
     105           22498 :     }
     106                 : 
     107                 :     void purgeAll();
     108                 : 
     109                 :     bool empty() const {
     110                 :         return all.empty();
     111                 :     }
     112                 : 
     113                 :     /* Fallibly aquire one of the supported map types from the pool. */
     114                 :     template <typename T>
     115                 :     T *acquire();
     116                 : 
     117                 :     /* Release one of the supported map types back to the pool. */
     118                 : 
     119         1206130 :     void release(AtomIndexMap *map) {
     120         1206130 :         recycle((void *) map);
     121         1206130 :     }
     122                 : 
     123         1114568 :     void release(AtomDefnMap *map) {
     124         1114568 :         recycle((void *) map);
     125         1114568 :     }
     126                 : 
     127         1115154 :     void release(AtomDOHMap *map) {
     128         1115154 :         recycle((void *) map);
     129         1115154 :     }
     130                 : }; /* ParseMapPool */
     131                 : 
     132                 : /*
     133                 :  * N.B. This is a POD-type so that it can be included in the ParseNode union.
     134                 :  * If possible, use the corresponding |OwnedAtomThingMapPtr| variant.
     135                 :  */
     136                 : template <class Map>
     137                 : struct AtomThingMapPtr
     138         5422640 : {
     139                 :     Map *map_;
     140                 : 
     141         6532354 :     void init() { clearMap(); }
     142                 : 
     143         2441778 :     bool ensureMap(JSContext *cx);
     144         6233903 :     void releaseMap(JSContext *cx);
     145                 : 
     146         2799300 :     bool hasMap() const { return map_; }
     147         1109121 :     Map *getMap() { return map_; }
     148                 :     void setMap(Map *newMap) { JS_ASSERT(!map_); map_ = newMap; }
     149         8155259 :     void clearMap() { map_ = NULL; }
     150                 : 
     151        80491138 :     Map *operator->() { return map_; }
     152           83617 :     const Map *operator->() const { return map_; }
     153                 :     Map &operator*() const { return *map_; }
     154                 : };
     155                 : 
     156                 : struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
     157         2093498 : {
     158                 :     JS_ALWAYS_INLINE
     159         3533094 :     Definition *lookupDefn(JSAtom *atom) {
     160         3533094 :         AtomDefnMap::Ptr p = map_->lookup(atom);
     161         3533094 :         return p ? p.value() : NULL;
     162                 :     }
     163                 : };
     164                 : 
     165                 : typedef AtomThingMapPtr<AtomIndexMap> AtomIndexMapPtr;
     166                 : 
     167                 : /*
     168                 :  * Wrapper around an AtomThingMapPtr (or its derivatives) that automatically
     169                 :  * releases a map on destruction, if one has been acquired.
     170                 :  */
     171                 : template <typename AtomThingMapPtrT>
     172                 : class OwnedAtomThingMapPtr : public AtomThingMapPtrT
     173                 : {
     174                 :     JSContext *cx;
     175                 : 
     176                 :   public:
     177         5422640 :     explicit OwnedAtomThingMapPtr(JSContext *cx) : cx(cx) {
     178         5422640 :         AtomThingMapPtrT::init();
     179         5422640 :     }
     180                 : 
     181         5422640 :     ~OwnedAtomThingMapPtr() {
     182         5422640 :         AtomThingMapPtrT::releaseMap(cx);
     183         5422640 :     }
     184                 : };
     185                 : 
     186                 : typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
     187                 : typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
     188                 : 
     189                 : /* Node structure for chaining in AtomDecls. */
     190                 : struct AtomDeclNode
     191                 : {
     192                 :     Definition *defn;
     193                 :     AtomDeclNode *next;
     194                 : 
     195          754363 :     explicit AtomDeclNode(Definition *defn)
     196          754363 :       : defn(defn), next(NULL)
     197          754363 :     {}
     198                 : };
     199                 : 
     200                 : /*
     201                 :  * Tagged union of a Definition and an AtomDeclNode, for use in AtomDecl's
     202                 :  * internal map.
     203                 :  */
     204                 : class DefnOrHeader
     205                 : {
     206                 :     union {
     207                 :         Definition    *defn;
     208                 :         AtomDeclNode    *head;
     209                 :         uintptr_t       bits;
     210                 :     } u;
     211                 : 
     212                 :   public:
     213         2473773 :     DefnOrHeader() {
     214         2473773 :         u.bits = 0;
     215         2473773 :     }
     216                 : 
     217         2561368 :     explicit DefnOrHeader(Definition *defn) {
     218         2561368 :         u.defn = defn;
     219         2561368 :         JS_ASSERT(!isHeader());
     220         2561368 :     }
     221                 : 
     222          756768 :     explicit DefnOrHeader(AtomDeclNode *node) {
     223          756768 :         u.head = node;
     224          756768 :         u.bits |= 0x1;
     225          756768 :         JS_ASSERT(isHeader());
     226          756768 :     }
     227                 : 
     228        19715360 :     bool isHeader() const {
     229        19715360 :         return u.bits & 0x1;
     230                 :     }
     231                 : 
     232         6519616 :     Definition *defn() const {
     233         6519616 :         JS_ASSERT(!isHeader());
     234         6519616 :         return u.defn;
     235                 :     }
     236                 : 
     237         1678962 :     AtomDeclNode *header() const {
     238         1678962 :         JS_ASSERT(isHeader());
     239         1678962 :         return (AtomDeclNode *) (u.bits & ~0x1);
     240                 :     }
     241                 : 
     242                 : #ifdef DEBUG
     243                 :     void dump();
     244                 : #endif
     245                 : };
     246                 : 
     247                 : namespace tl {
     248                 : 
     249                 : template <> struct IsPodType<DefnOrHeader> {
     250                 :     static const bool result = true;
     251                 : };
     252                 : 
     253                 : } /* namespace tl */
     254                 : 
     255                 : /*
     256                 :  * Multimap for function-scope atom declarations.
     257                 :  *
     258                 :  * Wraps an internal DeclOrHeader map with multi-map functionality.
     259                 :  *
     260                 :  * In the common case, no block scoping is used, and atoms have a single
     261                 :  * associated definition. In the uncommon (block scoping) case, we map the atom
     262                 :  * to a chain of definition nodes.
     263                 :  */
     264                 : class AtomDecls
     265                 : {
     266                 :     /* AtomDeclsIter needs to get at the DOHMap directly. */
     267                 :     friend class AtomDeclsIter;
     268                 : 
     269                 :     JSContext   *cx;
     270                 :     AtomDOHMap  *map;
     271                 : 
     272                 :     AtomDecls(const AtomDecls &other) MOZ_DELETE;
     273                 :     void operator=(const AtomDecls &other) MOZ_DELETE;
     274                 : 
     275                 :     AtomDeclNode *allocNode(Definition *defn);
     276                 : 
     277                 :     /*
     278                 :      * Fallibly return the value in |doh| as a node.
     279                 :      * Update the defn currently occupying |doh| to a node if necessary.
     280                 :      */
     281                 :     AtomDeclNode *lastAsNode(DefnOrHeader *doh);
     282                 : 
     283                 :   public:
     284         2093498 :     explicit AtomDecls(JSContext *cx)
     285         2093498 :       : cx(cx), map(NULL)
     286         2093498 :     {}
     287                 : 
     288                 :     ~AtomDecls();
     289                 : 
     290                 :     bool init();
     291                 : 
     292                 :     void clear() {
     293                 :         map->clear();
     294                 :     }
     295                 : 
     296                 :     /* Return the definition at the head of the chain for |atom|. */
     297                 :     inline Definition *lookupFirst(JSAtom *atom);
     298                 : 
     299                 :     /* Perform a lookup that can iterate over the definitions associated with |atom|. */
     300                 :     inline MultiDeclRange lookupMulti(JSAtom *atom);
     301                 : 
     302                 :     /* Add-or-update a known-unique definition for |atom|. */
     303                 :     inline bool addUnique(JSAtom *atom, Definition *defn);
     304                 :     bool addShadow(JSAtom *atom, Definition *defn);
     305                 :     bool addHoist(JSAtom *atom, Definition *defn);
     306                 : 
     307                 :     /* Updating the definition for an entry that is known to exist is infallible. */
     308              68 :     void updateFirst(JSAtom *atom, Definition *defn) {
     309              68 :         JS_ASSERT(map);
     310              68 :         AtomDOHMap::Ptr p = map->lookup(atom);
     311              68 :         JS_ASSERT(p);
     312              68 :         if (p.value().isHeader())
     313              18 :             p.value().header()->defn = defn;
     314                 :         else
     315              50 :             p.value() = DefnOrHeader(defn);
     316              68 :     }
     317                 : 
     318                 :     /* Remove the node at the head of the chain for |atom|. */
     319          750968 :     void remove(JSAtom *atom) {
     320          750968 :         JS_ASSERT(map);
     321          750968 :         AtomDOHMap::Ptr p = map->lookup(atom);
     322          750968 :         if (!p)
     323               0 :             return;
     324                 : 
     325          750968 :         DefnOrHeader &doh = p.value();
     326          750968 :         if (!doh.isHeader()) {
     327               0 :             map->remove(p);
     328               0 :             return;
     329                 :         }
     330                 : 
     331          750968 :         AtomDeclNode *node = doh.header();
     332          750968 :         AtomDeclNode *newHead = node->next;
     333          750968 :         if (newHead)
     334            5764 :             p.value() = DefnOrHeader(newHead);
     335                 :         else
     336          745204 :             map->remove(p);
     337                 :     }
     338                 : 
     339          265193 :     AtomDOHMap::Range all() {
     340          265193 :         JS_ASSERT(map);
     341          265193 :         return map->all();
     342                 :     }
     343                 : 
     344                 : #ifdef DEBUG
     345                 :     void dump();
     346                 : #endif
     347                 : };
     348                 : 
     349                 : /*
     350                 :  * Lookup state tracker for those situations where the caller wants to traverse
     351                 :  * multiple definitions associated with a single atom. This occurs due to block
     352                 :  * scoping.
     353                 :  */
     354                 : class MultiDeclRange
     355                 : {
     356                 :     friend class AtomDecls;
     357                 : 
     358                 :     AtomDeclNode *node;
     359                 :     Definition *defn;
     360                 : 
     361        14064148 :     explicit MultiDeclRange(Definition *defn) : node(NULL), defn(defn) {}
     362          899969 :     explicit MultiDeclRange(AtomDeclNode *node) : node(node), defn(node->defn) {}
     363                 : 
     364                 :   public:
     365               9 :     void popFront() {
     366               9 :         JS_ASSERT(!empty());
     367               9 :         if (!node) {
     368               0 :             defn = NULL;
     369               0 :             return;
     370                 :         }
     371               9 :         node = node->next;
     372               9 :         defn = node ? node->defn : NULL;
     373                 :     }
     374                 : 
     375         5678822 :     Definition *front() {
     376         5678822 :         JS_ASSERT(!empty());
     377         5678822 :         return defn;
     378                 :     }
     379                 : 
     380        21782021 :     bool empty() const {
     381        21782021 :         JS_ASSERT_IF(!defn, !node);
     382        21782021 :         return !defn;
     383                 :     }
     384                 : };
     385                 : 
     386                 : /* Iterates over all the definitions in an AtomDecls. */
     387                 : class AtomDeclsIter
     388                 : {
     389                 :     AtomDOHMap::Range   r;     /* Range over the map. */
     390                 :     AtomDeclNode        *link; /* Optional next node in the current atom's chain. */
     391                 : 
     392                 :   public:
     393          265193 :     explicit AtomDeclsIter(AtomDecls *decls) : r(decls->all()), link(NULL) {}
     394                 : 
     395          896765 :     Definition *operator()() {
     396          896765 :         if (link) {
     397               0 :             JS_ASSERT(link != link->next);
     398               0 :             Definition *result = link->defn;
     399               0 :             link = link->next;
     400               0 :             JS_ASSERT(result);
     401               0 :             return result;
     402                 :         }
     403                 : 
     404          896765 :         if (r.empty())
     405          258512 :             return NULL;
     406                 : 
     407          638253 :         const DefnOrHeader &doh = r.front().value();
     408          638253 :         r.popFront();
     409                 : 
     410          638253 :         if (!doh.isHeader())
     411          637558 :             return doh.defn();
     412                 : 
     413             695 :         JS_ASSERT(!link);
     414             695 :         AtomDeclNode *node = doh.header();
     415             695 :         link = node->next;
     416             695 :         return node->defn;
     417                 :     }
     418                 : };
     419                 : 
     420                 : typedef AtomDefnMap::Range      AtomDefnRange;
     421                 : typedef AtomDefnMap::AddPtr     AtomDefnAddPtr;
     422                 : typedef AtomDefnMap::Ptr        AtomDefnPtr;
     423                 : typedef AtomIndexMap::AddPtr    AtomIndexAddPtr;
     424                 : typedef AtomIndexMap::Ptr       AtomIndexPtr;
     425                 : typedef AtomDOHMap::Ptr         AtomDOHPtr;
     426                 : typedef AtomDOHMap::AddPtr      AtomDOHAddPtr;
     427                 : typedef AtomDOHMap::Range       AtomDOHRange;
     428                 : 
     429                 : } /* namepsace js */
     430                 : 
     431                 : #endif

Generated by: LCOV version 1.7