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