js/src/frontend/ParseMaps.h

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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 */

mercurial