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:
4
* This Source Code Form is subject to the terms of the Mozilla Public
5
* License, v. 2.0. If a copy of the MPL was not distributed with this
6
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11
#include "mozilla/Attributes.h"
13
#include "ds/InlineMap.h"
14
#include "js/HashTable.h"
15
#include "js/Vector.h"
23
typedef InlineMap<JSAtom *, jsatomid, 24> AtomIndexMap;
24
typedef InlineMap<JSAtom *, Definition *, 24> AtomDefnMap;
25
typedef InlineMap<JSAtom *, DefinitionList, 24> AtomDefnListMap;
28
* For all unmapped atoms recorded in al, add a mapping from the atom's index
29
* to its address. map->length must already be set to the number of atoms in
30
* the list and map->vector must point to pre-allocated memory.
33
InitAtomMap(JSContext *cx, AtomIndexMap *indices, HeapPtr<JSAtom> *atoms);
36
* A pool that permits the reuse of the backing storage for the defn, index, or
37
* defn-or-header (multi) maps.
39
* The pool owns all the maps that are given out, and is responsible for
40
* relinquishing all resources when |purgeAll| is triggered.
44
typedef Vector<void *, 32, SystemAllocPolicy> RecyclableMaps;
47
RecyclableMaps recyclable;
50
void checkInvariants();
52
void recycle(void *map) {
56
/* Make sure the map is in |all| but not already in |recyclable|. */
57
for (void **it = all.begin(), **end = all.end(); it != end; ++it) {
64
for (void **it = recyclable.begin(), **end = recyclable.end(); it != end; ++it)
65
JS_ASSERT(*it != map);
67
JS_ASSERT(recyclable.length() < all.length());
68
recyclable.infallibleAppend(map); /* Reserved in allocateFresh. */
71
void *allocateFresh();
74
/* Arbitrary atom map type, that has keys and values of the same kind. */
75
typedef AtomIndexMap AtomMapT;
77
static AtomMapT *asAtomMap(void *ptr) {
78
return reinterpret_cast<AtomMapT *>(ptr);
82
explicit ParseMapPool(JSContext *cx) : cx(cx) {}
94
/* Fallibly aquire one of the supported map types from the pool. */
98
/* Release one of the supported map types back to the pool. */
100
void release(AtomIndexMap *map) {
101
recycle((void *) map);
104
void release(AtomDefnMap *map) {
105
recycle((void *) map);
108
void release(AtomDefnListMap *map) {
109
recycle((void *) map);
111
}; /* ParseMapPool */
114
* N.B. This is a POD-type so that it can be included in the ParseNode union.
115
* If possible, use the corresponding |OwnedAtomThingMapPtr| variant.
118
struct AtomThingMapPtr
122
void init() { clearMap(); }
124
bool ensureMap(JSContext *cx);
125
void releaseMap(JSContext *cx);
127
bool hasMap() const { return map_; }
128
Map *getMap() { return map_; }
129
void setMap(Map *newMap) { JS_ASSERT(!map_); map_ = newMap; }
130
void clearMap() { map_ = NULL; }
132
Map *operator->() { return map_; }
133
const Map *operator->() const { return map_; }
134
Map &operator*() const { return *map_; }
137
struct AtomDefnMapPtr : public AtomThingMapPtr<AtomDefnMap>
140
Definition *lookupDefn(JSAtom *atom) {
141
AtomDefnMap::Ptr p = map_->lookup(atom);
142
return p ? p.value() : NULL;
146
typedef AtomThingMapPtr<AtomIndexMap> AtomIndexMapPtr;
149
* Wrapper around an AtomThingMapPtr (or its derivatives) that automatically
150
* releases a map on destruction, if one has been acquired.
152
template <typename AtomThingMapPtrT>
153
class OwnedAtomThingMapPtr : public AtomThingMapPtrT
158
explicit OwnedAtomThingMapPtr(JSContext *cx) : cx(cx) {
159
AtomThingMapPtrT::init();
162
~OwnedAtomThingMapPtr() {
163
AtomThingMapPtrT::releaseMap(cx);
167
typedef OwnedAtomThingMapPtr<AtomDefnMapPtr> OwnedAtomDefnMapPtr;
168
typedef OwnedAtomThingMapPtr<AtomIndexMapPtr> OwnedAtomIndexMapPtr;
171
* A nonempty list containing one or more pointers to Definitions.
173
* By far the most common case is that the list contains exactly one
174
* Definition, so the implementation is optimized for that case.
176
* Nodes for the linked list (if any) are allocated from the tempPool of a
177
* context the caller passes into pushFront and pushBack. This means the
178
* DefinitionList does not own the memory for the nodes: the JSContext does.
179
* As a result, DefinitionList is a POD type; it can be safely and cheaply
190
/* A node in a linked list of Definitions. */
196
Node(Definition *defn, Node *next) : defn(defn), next(next) {}
205
Definition *defn() const {
206
JS_ASSERT(!isMultiple());
210
Node *firstNode() const {
211
JS_ASSERT(isMultiple());
212
return (Node *) (u.bits & ~0x1);
216
allocNode(JSContext *cx, Definition *head, Node *tail);
221
friend class DefinitionList;
226
explicit Range(const DefinitionList &list) {
227
if (list.isMultiple()) {
228
node = list.firstNode();
237
/* An empty Range. */
238
Range() : node(NULL), defn(NULL) {}
247
defn = node ? node->defn : NULL;
250
Definition *front() {
256
JS_ASSERT_IF(!defn, !node);
265
explicit DefinitionList(Definition *defn) {
267
JS_ASSERT(!isMultiple());
270
explicit DefinitionList(Node *node) {
273
JS_ASSERT(isMultiple());
276
bool isMultiple() const { return (u.bits & 0x1) != 0; }
278
Definition *front() {
279
return isMultiple() ? firstNode()->defn : defn();
283
* If there are multiple Definitions in this list, remove the first and
284
* return true. Otherwise there is exactly one Definition in the list; do
285
* nothing and return false.
291
Node *node = firstNode();
292
Node *next = node->next;
294
*this = DefinitionList(next);
296
*this = DefinitionList(next->defn);
301
* Add a definition to the front of this list.
303
* Return true on success. On OOM, report on cx and return false.
305
bool pushFront(JSContext *cx, Definition *val);
307
/* Like pushFront, but add the given val to the end of the list. */
308
bool pushBack(JSContext *cx, Definition *val);
310
/* Overwrite the first Definition in the list. */
311
void setFront(Definition *val) {
313
firstNode()->defn = val;
315
*this = DefinitionList(val);
318
Range all() const { return Range(*this); }
326
* AtomDecls is a map of atoms to (sequences of) Definitions. It is used by
327
* ParseContext to store declarations. A declaration associates a name with a
330
* Declarations with function scope (such as const, var, and function) are
331
* unique in the sense that they override any previous declarations with the
332
* same name. For such declarations, we only need to store a single Definition,
333
* using the method addUnique.
335
* Declarations with block scope (such as let) are slightly more complex. They
336
* override any previous declarations with the same name, but only do so for
337
* the block they are associated with. This is known as shadowing. For such
338
* definitions, we need to store a sequence of Definitions, including those
339
* introduced by previous declarations (and which are now shadowed), using the
340
* method addShadow. When we leave the block associated with the let, the method
341
* remove is used to unshadow the declaration immediately preceding it.
345
/* AtomDeclsIter needs to get at the DefnListMap directly. */
346
friend class AtomDeclsIter;
349
AtomDefnListMap *map;
351
AtomDecls(const AtomDecls &other) MOZ_DELETE;
352
void operator=(const AtomDecls &other) MOZ_DELETE;
355
explicit AtomDecls(JSContext *cx) : cx(cx), map(NULL) {}
365
/* Return the definition at the head of the chain for |atom|. */
366
inline Definition *lookupFirst(JSAtom *atom) const;
368
/* Perform a lookup that can iterate over the definitions associated with |atom|. */
369
inline DefinitionList::Range lookupMulti(JSAtom *atom) const;
371
/* Add-or-update a known-unique definition for |atom|. */
372
inline bool addUnique(JSAtom *atom, Definition *defn);
373
bool addShadow(JSAtom *atom, Definition *defn);
375
/* Updating the definition for an entry that is known to exist is infallible. */
376
void updateFirst(JSAtom *atom, Definition *defn) {
378
AtomDefnListMap::Ptr p = map->lookup(atom);
380
p.value().setFront(defn);
383
/* Remove the node at the head of the chain for |atom|. */
384
void remove(JSAtom *atom) {
386
AtomDefnListMap::Ptr p = map->lookup(atom);
390
DefinitionList &list = p.value();
391
if (!list.popFront()) {
397
AtomDefnListMap::Range all() const {
407
typedef AtomDefnMap::Range AtomDefnRange;
408
typedef AtomDefnMap::AddPtr AtomDefnAddPtr;
409
typedef AtomDefnMap::Ptr AtomDefnPtr;
410
typedef AtomIndexMap::AddPtr AtomIndexAddPtr;
411
typedef AtomIndexMap::Ptr AtomIndexPtr;
412
typedef AtomDefnListMap::Ptr AtomDefnListPtr;
413
typedef AtomDefnListMap::AddPtr AtomDefnListAddPtr;
414
typedef AtomDefnListMap::Range AtomDefnListRange;
416
} /* namespace frontend */
420
template <> struct IsPodType<frontend::DefinitionList> {
421
static const bool result = true;