Sat, 03 Jan 2015 20:18:00 +0100
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 */ |