js/src/frontend/ParseMaps.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #ifndef frontend_ParseMaps_h
     8 #define frontend_ParseMaps_h
    10 #include "mozilla/Attributes.h"
    11 #include "mozilla/TypeTraits.h"
    13 #include "ds/InlineMap.h"
    14 #include "gc/Barrier.h"
    15 #include "js/Vector.h"
    17 class JSAtom;
    19 typedef uintptr_t jsatomid;
    21 namespace js {
    23 class LifoAlloc;
    25 namespace frontend {
    27 class DefinitionSingle;
    28 class DefinitionList;
    30 typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
    31 typedef InlineMap<JSAtom *, DefinitionSingle, 24> AtomDefnMap;
    32 typedef InlineMap<JSAtom *, DefinitionList, 24> AtomDefnListMap;
    34 /*
    35  * For all unmapped atoms recorded in al, add a mapping from the atom's index
    36  * to its address. map->length must already be set to the number of atoms in
    37  * the list and map->vector must point to pre-allocated memory.
    38  */
    39 void
    40 InitAtomMap(AtomIndexMap *indices, HeapPtr<JSAtom> *atoms);
    42 /*
    43  * A pool that permits the reuse of the backing storage for the defn, index, or
    44  * defn-or-header (multi) maps.
    45  *
    46  * The pool owns all the maps that are given out, and is responsible for
    47  * relinquishing all resources when |purgeAll| is triggered.
    48  */
    49 class ParseMapPool
    50 {
    51     typedef Vector<void *, 32, SystemAllocPolicy> RecyclableMaps;
    53     RecyclableMaps      all;
    54     RecyclableMaps      recyclable;
    56     void checkInvariants();
    58     void recycle(void *map) {
    59         JS_ASSERT(map);
    60 #ifdef DEBUG
    61         bool ok = false;
    62         /* Make sure the map is in |all| but not already in |recyclable|. */
    63         for (void **it = all.begin(), **end = all.end(); it != end; ++it) {
    64             if (*it == map) {
    65                 ok = true;
    66                 break;
    67             }
    68         }
    69         JS_ASSERT(ok);
    70         for (void **it = recyclable.begin(), **end = recyclable.end(); it != end; ++it)
    71             JS_ASSERT(*it != map);
    72 #endif
    73         JS_ASSERT(recyclable.length() < all.length());
    74         recyclable.infallibleAppend(map); /* Reserved in allocateFresh. */
    75     }
    77     void *allocateFresh();
    78     void *allocate() {
    79         if (recyclable.empty())
    80             return allocateFresh();
    82         void *map = recyclable.popCopy();
    83         asAtomMap(map)->clear();
    84         return map;
    85     }
    87     /* Arbitrary atom map type, that has keys and values of the same kind. */
    88     typedef AtomIndexMap AtomMapT;
    90     static AtomMapT *asAtomMap(void *ptr) {
    91         return reinterpret_cast<AtomMapT *>(ptr);
    92     }
    94   public:
    95     ~ParseMapPool() {
    96         purgeAll();
    97     }
    99     void purgeAll();
   101     bool empty() const {
   102         return all.empty();
   103     }
   105     /* Fallibly aquire one of the supported map types from the pool. */
   106     template <typename T>
   107     T *acquire() {
   108         return reinterpret_cast<T *>(allocate());
   109     }
   111     /* Release one of the supported map types back to the pool. */
   113     void release(AtomIndexMap *map) {
   114         recycle((void *) map);
   115     }
   117     void release(AtomDefnMap *map) {
   118         recycle((void *) map);
   119     }
   121     void release(AtomDefnListMap *map) {
   122         recycle((void *) map);
   123     }
   124 }; /* ParseMapPool */
   126 /*
   127  * N.B. This is a POD-type so that it can be included in the ParseNode union.
   128  * If possible, use the corresponding |OwnedAtomThingMapPtr| variant.
   129  */
   130 template <class Map>
   131 struct AtomThingMapPtr
   132 {
   133     Map *map_;
   135     void init() { clearMap(); }
   137     bool ensureMap(ExclusiveContext *cx);
   138     void releaseMap(ExclusiveContext *cx);
   140     bool hasMap() const { return map_; }
   141     Map *getMap() { return map_; }
   142     void setMap(Map *newMap) { JS_ASSERT(!map_); map_ = newMap; }
   143     void clearMap() { map_ = nullptr; }
   145     Map *operator->() { return map_; }
   146     const Map *operator->() const { return map_; }
   147     Map &operator*() const { return *map_; }
   148 };
   150 typedef AtomThingMapPtr<AtomIndexMap> AtomIndexMapPtr;
   152 /*
   153  * Wrapper around an AtomThingMapPtr (or its derivatives) that automatically
   154  * releases a map on destruction, if one has been acquired.
   155  */
   156 template <typename AtomThingMapPtrT>
   157 class OwnedAtomThingMapPtr : public AtomThingMapPtrT
   158 {
   159     ExclusiveContext *cx;
   161   public:
   162     explicit OwnedAtomThingMapPtr(ExclusiveContext *cx) : cx(cx) {
   163         AtomThingMapPtrT::init();
   164     }
   166     ~OwnedAtomThingMapPtr() {
   167         AtomThingMapPtrT::releaseMap(cx);
   168     }
   169 };
   171 typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
   173 /*
   174  * DefinitionSingle and DefinitionList represent either a single definition
   175  * or a list of them. The representation of definitions varies between
   176  * parse handlers, being either a Definition* (FullParseHandler) or a
   177  * Definition::Kind (SyntaxParseHandler). Methods on the below classes are
   178  * templated to distinguish the kind of value wrapped by the class.
   179  */
   181 /* Wrapper for a single definition. */
   182 class DefinitionSingle
   183 {
   184     uintptr_t bits;
   186   public:
   188     template <typename ParseHandler>
   189     static DefinitionSingle new_(typename ParseHandler::DefinitionNode defn)
   190     {
   191         DefinitionSingle res;
   192         res.bits = ParseHandler::definitionToBits(defn);
   193         return res;
   194     }
   196     template <typename ParseHandler>
   197     typename ParseHandler::DefinitionNode get() {
   198         return ParseHandler::definitionFromBits(bits);
   199     }
   200 };
   202 struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
   203 {
   204     template <typename ParseHandler>
   205     MOZ_ALWAYS_INLINE
   206     typename ParseHandler::DefinitionNode lookupDefn(JSAtom *atom) {
   207         AtomDefnMap::Ptr p = map_->lookup(atom);
   208         return p ? p.value().get<ParseHandler>() : ParseHandler::nullDefinition();
   209     }
   210 };
   212 typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
   214 /*
   215  * A nonempty list containing one or more pointers to Definitions.
   216  *
   217  * By far the most common case is that the list contains exactly one
   218  * Definition, so the implementation is optimized for that case.
   219  *
   220  * Nodes for the linked list (if any) are allocated from the tempPool of a
   221  * context the caller passes into pushFront and pushBack. This means the
   222  * DefinitionList does not own the memory for the nodes: the JSContext does.
   223  * As a result, DefinitionList is a POD type; it can be safely and cheaply
   224  * copied.
   225  */
   226 class DefinitionList
   227 {
   228   public:
   229     class Range;
   231   private:
   232     friend class Range;
   234     /* A node in a linked list of Definitions. */
   235     struct Node
   236     {
   237         uintptr_t bits;
   238         Node *next;
   240         Node(uintptr_t bits, Node *next) : bits(bits), next(next) {}
   241     };
   243     union {
   244         uintptr_t bits;
   245         Node *head;
   246     } u;
   248     Node *firstNode() const {
   249         JS_ASSERT(isMultiple());
   250         return (Node *) (u.bits & ~0x1);
   251     }
   253     static Node *
   254     allocNode(ExclusiveContext *cx, LifoAlloc &alloc, uintptr_t bits, Node *tail);
   256   public:
   257     class Range
   258     {
   259         friend class DefinitionList;
   261         Node *node;
   262         uintptr_t bits;
   264         explicit Range(const DefinitionList &list) {
   265             if (list.isMultiple()) {
   266                 node = list.firstNode();
   267                 bits = node->bits;
   268             } else {
   269                 node = nullptr;
   270                 bits = list.u.bits;
   271             }
   272         }
   274       public:
   275         /* An empty Range. */
   276         Range() : node(nullptr), bits(0) {}
   278         void popFront() {
   279             JS_ASSERT(!empty());
   280             if (!node) {
   281                 bits = 0;
   282                 return;
   283             }
   284             node = node->next;
   285             bits = node ? node->bits : 0;
   286         }
   288         template <typename ParseHandler>
   289         typename ParseHandler::DefinitionNode front() {
   290             JS_ASSERT(!empty());
   291             return ParseHandler::definitionFromBits(bits);
   292         }
   294         bool empty() const {
   295             JS_ASSERT_IF(!bits, !node);
   296             return !bits;
   297         }
   298     };
   300     DefinitionList() {
   301         u.bits = 0;
   302     }
   304     explicit DefinitionList(uintptr_t bits) {
   305         u.bits = bits;
   306         JS_ASSERT(!isMultiple());
   307     }
   309     explicit DefinitionList(Node *node) {
   310         u.head = node;
   311         u.bits |= 0x1;
   312         JS_ASSERT(isMultiple());
   313     }
   315     bool isMultiple() const { return (u.bits & 0x1) != 0; }
   317     template <typename ParseHandler>
   318     typename ParseHandler::DefinitionNode front() {
   319         return ParseHandler::definitionFromBits(isMultiple() ? firstNode()->bits : u.bits);
   320     }
   322     /*
   323      * If there are multiple Definitions in this list, remove the first and
   324      * return true. Otherwise there is exactly one Definition in the list; do
   325      * nothing and return false.
   326      */
   327     bool popFront() {
   328         if (!isMultiple())
   329             return false;
   331         Node *node = firstNode();
   332         Node *next = node->next;
   333         if (next->next)
   334             *this = DefinitionList(next);
   335         else
   336             *this = DefinitionList(next->bits);
   337         return true;
   338     }
   340     /*
   341      * Add a definition to the front of this list.
   342      *
   343      * Return true on success. On OOM, report on cx and return false.
   344      */
   345     template <typename ParseHandler>
   346     bool pushFront(ExclusiveContext *cx, LifoAlloc &alloc,
   347                    typename ParseHandler::DefinitionNode defn) {
   348         Node *tail;
   349         if (isMultiple()) {
   350             tail = firstNode();
   351         } else {
   352             tail = allocNode(cx, alloc, u.bits, nullptr);
   353             if (!tail)
   354                 return false;
   355         }
   357         Node *node = allocNode(cx, alloc, ParseHandler::definitionToBits(defn), tail);
   358         if (!node)
   359             return false;
   360         *this = DefinitionList(node);
   361         return true;
   362     }
   364     /* Overwrite the first Definition in the list. */
   365     template <typename ParseHandler>
   366         void setFront(typename ParseHandler::DefinitionNode defn) {
   367         if (isMultiple())
   368             firstNode()->bits = ParseHandler::definitionToBits(defn);
   369         else
   370             *this = DefinitionList(ParseHandler::definitionToBits(defn));
   371     }
   373     Range all() const { return Range(*this); }
   375 #ifdef DEBUG
   376     void dump();
   377 #endif
   378 };
   380 typedef AtomDefnMap::Range      AtomDefnRange;
   381 typedef AtomDefnMap::AddPtr     AtomDefnAddPtr;
   382 typedef AtomDefnMap::Ptr        AtomDefnPtr;
   383 typedef AtomIndexMap::AddPtr    AtomIndexAddPtr;
   384 typedef AtomIndexMap::Ptr       AtomIndexPtr;
   385 typedef AtomDefnListMap::Ptr    AtomDefnListPtr;
   386 typedef AtomDefnListMap::AddPtr AtomDefnListAddPtr;
   387 typedef AtomDefnListMap::Range  AtomDefnListRange;
   389 /*
   390  * AtomDecls is a map of atoms to (sequences of) Definitions. It is used by
   391  * ParseContext to store declarations. A declaration associates a name with a
   392  * Definition.
   393  *
   394  * Declarations with function scope (such as const, var, and function) are
   395  * unique in the sense that they override any previous declarations with the
   396  * same name. For such declarations, we only need to store a single Definition,
   397  * using the method addUnique.
   398  *
   399  * Declarations with block scope (such as let) are slightly more complex. They
   400  * override any previous declarations with the same name, but only do so for
   401  * the block they are associated with. This is known as shadowing. For such
   402  * definitions, we need to store a sequence of Definitions, including those
   403  * introduced by previous declarations (and which are now shadowed), using the
   404  * method addShadow. When we leave the block associated with the let, the method
   405  * remove is used to unshadow the declaration immediately preceding it.
   406  */
   407 template <typename ParseHandler>
   408 class AtomDecls
   409 {
   410     typedef typename ParseHandler::DefinitionNode DefinitionNode;
   412     /* AtomDeclsIter needs to get at the DefnListMap directly. */
   413     friend class AtomDeclsIter;
   415     ExclusiveContext *cx;
   416     LifoAlloc &alloc;
   417     AtomDefnListMap  *map;
   419     AtomDecls(const AtomDecls &other) MOZ_DELETE;
   420     void operator=(const AtomDecls &other) MOZ_DELETE;
   422   public:
   423     explicit AtomDecls(ExclusiveContext *cx, LifoAlloc &alloc) : cx(cx),
   424                                                                  alloc(alloc),
   425                                                                  map(nullptr) {}
   427     ~AtomDecls();
   429     bool init();
   431     void clear() {
   432         map->clear();
   433     }
   435     /* Return the definition at the head of the chain for |atom|. */
   436     DefinitionNode lookupFirst(JSAtom *atom) const {
   437         JS_ASSERT(map);
   438         AtomDefnListPtr p = map->lookup(atom);
   439         if (!p)
   440             return ParseHandler::nullDefinition();
   441         return p.value().front<ParseHandler>();
   442     }
   444     /* Perform a lookup that can iterate over the definitions associated with |atom|. */
   445     DefinitionList::Range lookupMulti(JSAtom *atom) const {
   446         JS_ASSERT(map);
   447         if (AtomDefnListPtr p = map->lookup(atom))
   448             return p.value().all();
   449         return DefinitionList::Range();
   450     }
   452     /* Add-or-update a known-unique definition for |atom|. */
   453     bool addUnique(JSAtom *atom, DefinitionNode defn) {
   454         JS_ASSERT(map);
   455         AtomDefnListAddPtr p = map->lookupForAdd(atom);
   456         if (!p)
   457             return map->add(p, atom, DefinitionList(ParseHandler::definitionToBits(defn)));
   458         JS_ASSERT(!p.value().isMultiple());
   459         p.value() = DefinitionList(ParseHandler::definitionToBits(defn));
   460         return true;
   461     }
   463     bool addShadow(JSAtom *atom, DefinitionNode defn);
   465     /* Updating the definition for an entry that is known to exist is infallible. */
   466     void updateFirst(JSAtom *atom, DefinitionNode defn) {
   467         JS_ASSERT(map);
   468         AtomDefnListMap::Ptr p = map->lookup(atom);
   469         JS_ASSERT(p);
   470         p.value().setFront<ParseHandler>(defn);
   471     }
   473     /* Remove the node at the head of the chain for |atom|. */
   474     void remove(JSAtom *atom) {
   475         JS_ASSERT(map);
   476         AtomDefnListMap::Ptr p = map->lookup(atom);
   477         if (!p)
   478             return;
   480         DefinitionList &list = p.value();
   481         if (!list.popFront()) {
   482             map->remove(p);
   483             return;
   484         }
   485     }
   487     AtomDefnListMap::Range all() const {
   488         JS_ASSERT(map);
   489         return map->all();
   490     }
   492 #ifdef DEBUG
   493     void dump();
   494 #endif
   495 };
   497 } /* namespace frontend */
   499 } /* namespace js */
   501 namespace mozilla {
   503 template <>
   504 struct IsPod<js::frontend::DefinitionSingle> : TrueType {};
   506 template <>
   507 struct IsPod<js::frontend::DefinitionList> : TrueType {};
   509 } /* namespace mozilla */
   511 #endif /* frontend_ParseMaps_h */

mercurial