js/src/gc/FindSCCs.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 gc_FindSCCs_h
michael@0 8 #define gc_FindSCCs_h
michael@0 9
michael@0 10 #include "jsfriendapi.h"
michael@0 11 #include "jsutil.h"
michael@0 12
michael@0 13 namespace js {
michael@0 14 namespace gc {
michael@0 15
michael@0 16 template<class Node>
michael@0 17 struct GraphNodeBase
michael@0 18 {
michael@0 19 Node *gcNextGraphNode;
michael@0 20 Node *gcNextGraphComponent;
michael@0 21 unsigned gcDiscoveryTime;
michael@0 22 unsigned gcLowLink;
michael@0 23
michael@0 24 GraphNodeBase()
michael@0 25 : gcNextGraphNode(nullptr),
michael@0 26 gcNextGraphComponent(nullptr),
michael@0 27 gcDiscoveryTime(0),
michael@0 28 gcLowLink(0) {}
michael@0 29
michael@0 30 ~GraphNodeBase() {}
michael@0 31
michael@0 32 Node *nextNodeInGroup() const {
michael@0 33 if (gcNextGraphNode && gcNextGraphNode->gcNextGraphComponent == gcNextGraphComponent)
michael@0 34 return gcNextGraphNode;
michael@0 35 return nullptr;
michael@0 36 }
michael@0 37
michael@0 38 Node *nextGroup() const {
michael@0 39 return gcNextGraphComponent;
michael@0 40 }
michael@0 41 };
michael@0 42
michael@0 43 /*
michael@0 44 * Find the strongly connected components of a graph using Tarjan's algorithm,
michael@0 45 * and return them in topological order.
michael@0 46 *
michael@0 47 * Nodes derive from GraphNodeBase and implement findGraphEdges, which calls
michael@0 48 * finder.addEdgeTo to describe the outgoing edges from that node:
michael@0 49 *
michael@0 50 * struct MyGraphNode : public GraphNodeBase
michael@0 51 * {
michael@0 52 * void findOutgoingEdges(ComponentFinder<MyGraphNode> &finder)
michael@0 53 * {
michael@0 54 * for edge in my_outgoing_edges:
michael@0 55 * if is_relevant(edge):
michael@0 56 * finder.addEdgeTo(edge.destination)
michael@0 57 * }
michael@0 58 * }
michael@0 59 *
michael@0 60 * ComponentFinder<MyGraphNode> finder;
michael@0 61 * finder.addNode(v);
michael@0 62 */
michael@0 63 template<class Node>
michael@0 64 class ComponentFinder
michael@0 65 {
michael@0 66 public:
michael@0 67 ComponentFinder(uintptr_t sl)
michael@0 68 : clock(1),
michael@0 69 stack(nullptr),
michael@0 70 firstComponent(nullptr),
michael@0 71 cur(nullptr),
michael@0 72 stackLimit(sl),
michael@0 73 stackFull(false)
michael@0 74 {}
michael@0 75
michael@0 76 ~ComponentFinder() {
michael@0 77 JS_ASSERT(!stack);
michael@0 78 JS_ASSERT(!firstComponent);
michael@0 79 }
michael@0 80
michael@0 81 /* Forces all nodes to be added to a single component. */
michael@0 82 void useOneComponent() { stackFull = true; }
michael@0 83
michael@0 84 void addNode(Node *v) {
michael@0 85 if (v->gcDiscoveryTime == Undefined) {
michael@0 86 JS_ASSERT(v->gcLowLink == Undefined);
michael@0 87 processNode(v);
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 Node *getResultsList() {
michael@0 92 if (stackFull) {
michael@0 93 /*
michael@0 94 * All nodes after the stack overflow are in |stack|. Put them all in
michael@0 95 * one big component of their own.
michael@0 96 */
michael@0 97 Node *firstGoodComponent = firstComponent;
michael@0 98 for (Node *v = stack; v; v = stack) {
michael@0 99 stack = v->gcNextGraphNode;
michael@0 100 v->gcNextGraphComponent = firstGoodComponent;
michael@0 101 v->gcNextGraphNode = firstComponent;
michael@0 102 firstComponent = v;
michael@0 103 }
michael@0 104 stackFull = false;
michael@0 105 }
michael@0 106
michael@0 107 JS_ASSERT(!stack);
michael@0 108
michael@0 109 Node *result = firstComponent;
michael@0 110 firstComponent = nullptr;
michael@0 111
michael@0 112 for (Node *v = result; v; v = v->gcNextGraphNode) {
michael@0 113 v->gcDiscoveryTime = Undefined;
michael@0 114 v->gcLowLink = Undefined;
michael@0 115 }
michael@0 116
michael@0 117 return result;
michael@0 118 }
michael@0 119
michael@0 120 static void mergeGroups(Node *first) {
michael@0 121 for (Node *v = first; v; v = v->gcNextGraphNode)
michael@0 122 v->gcNextGraphComponent = nullptr;
michael@0 123 }
michael@0 124
michael@0 125 public:
michael@0 126 /* Call from implementation of GraphNodeBase::findOutgoingEdges(). */
michael@0 127 void addEdgeTo(Node *w) {
michael@0 128 if (w->gcDiscoveryTime == Undefined) {
michael@0 129 processNode(w);
michael@0 130 cur->gcLowLink = Min(cur->gcLowLink, w->gcLowLink);
michael@0 131 } else if (w->gcDiscoveryTime != Finished) {
michael@0 132 cur->gcLowLink = Min(cur->gcLowLink, w->gcDiscoveryTime);
michael@0 133 }
michael@0 134 }
michael@0 135
michael@0 136 private:
michael@0 137 /* Constant used to indicate an unprocessed vertex. */
michael@0 138 static const unsigned Undefined = 0;
michael@0 139
michael@0 140 /* Constant used to indicate an processed vertex that is no longer on the stack. */
michael@0 141 static const unsigned Finished = (unsigned)-1;
michael@0 142
michael@0 143 void processNode(Node *v) {
michael@0 144 v->gcDiscoveryTime = clock;
michael@0 145 v->gcLowLink = clock;
michael@0 146 ++clock;
michael@0 147
michael@0 148 v->gcNextGraphNode = stack;
michael@0 149 stack = v;
michael@0 150
michael@0 151 int stackDummy;
michael@0 152 if (stackFull || !JS_CHECK_STACK_SIZE(stackLimit, &stackDummy)) {
michael@0 153 stackFull = true;
michael@0 154 return;
michael@0 155 }
michael@0 156
michael@0 157 Node *old = cur;
michael@0 158 cur = v;
michael@0 159 cur->findOutgoingEdges(*this);
michael@0 160 cur = old;
michael@0 161
michael@0 162 if (stackFull)
michael@0 163 return;
michael@0 164
michael@0 165 if (v->gcLowLink == v->gcDiscoveryTime) {
michael@0 166 Node *nextComponent = firstComponent;
michael@0 167 Node *w;
michael@0 168 do {
michael@0 169 JS_ASSERT(stack);
michael@0 170 w = stack;
michael@0 171 stack = w->gcNextGraphNode;
michael@0 172
michael@0 173 /*
michael@0 174 * Record that the element is no longer on the stack by setting the
michael@0 175 * discovery time to a special value that's not Undefined.
michael@0 176 */
michael@0 177 w->gcDiscoveryTime = Finished;
michael@0 178
michael@0 179 /* Figure out which group we're in. */
michael@0 180 w->gcNextGraphComponent = nextComponent;
michael@0 181
michael@0 182 /*
michael@0 183 * Prepend the component to the beginning of the output list to
michael@0 184 * reverse the list and achieve the desired order.
michael@0 185 */
michael@0 186 w->gcNextGraphNode = firstComponent;
michael@0 187 firstComponent = w;
michael@0 188 } while (w != v);
michael@0 189 }
michael@0 190 }
michael@0 191
michael@0 192 private:
michael@0 193 unsigned clock;
michael@0 194 Node *stack;
michael@0 195 Node *firstComponent;
michael@0 196 Node *cur;
michael@0 197 uintptr_t stackLimit;
michael@0 198 bool stackFull;
michael@0 199 };
michael@0 200
michael@0 201 } /* namespace gc */
michael@0 202 } /* namespace js */
michael@0 203
michael@0 204 #endif /* gc_FindSCCs_h */

mercurial