]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGDominators.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGDominators.cpp
CommitLineData
93a37866 1/*
ed1e77d3 2 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
93a37866
A
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "DFGDominators.h"
28
29#if ENABLE(DFG_JIT)
30
ed1e77d3
A
31#include "DFGBlockMapInlines.h"
32#include "DFGBlockWorklist.h"
93a37866 33#include "DFGGraph.h"
ed1e77d3 34#include "DFGNaiveDominators.h"
81345200 35#include "JSCInlines.h"
93a37866
A
36
37namespace JSC { namespace DFG {
38
39Dominators::Dominators()
93a37866
A
40{
41}
42
43Dominators::~Dominators()
44{
45}
46
ed1e77d3
A
47namespace {
48
49// This implements Lengauer and Tarjan's "A Fast Algorithm for Finding Dominators in a Flowgraph"
50// (TOPLAS 1979). It uses the "simple" implementation of LINK and EVAL, which yields an O(n log n)
51// solution. The full paper is linked below; this code attempts to closely follow the algorithm as
52// it is presented in the paper; in particular sections 3 and 4 as well as appendix B.
53// https://www.cs.princeton.edu/courses/archive/fall03/cs528/handouts/a%20fast%20algorithm%20for%20finding.pdf
54//
55// This code is very subtle. The Lengauer-Tarjan algorithm is incredibly deep to begin with. The
56// goal of this code is to follow the code in the paper, however our implementation must deviate
57// from the paper when it comes to recursion. The authors had used recursion to implement DFS, and
58// also to implement the "simple" EVAL. We convert both of those into worklist-based solutions.
59// Finally, once the algorithm gives us immediate dominators, we implement dominance tests by
60// walking the dominator tree and computing pre and post numbers. We then use the range inclusion
61// check trick that was first discovered by Paul F. Dietz in 1982 in "Maintaining order in a linked
62// list" (see http://dl.acm.org/citation.cfm?id=802184).
63
64class LengauerTarjan {
65public:
66 LengauerTarjan(Graph& graph)
67 : m_graph(graph)
68 , m_data(graph)
69 {
70 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
71 BasicBlock* block = m_graph.block(blockIndex);
72 if (!block)
73 continue;
74 m_data[block].label = block;
75 }
76 }
93a37866 77
ed1e77d3
A
78 void compute()
79 {
80 computeDepthFirstPreNumbering(); // Step 1.
81 computeSemiDominatorsAndImplicitImmediateDominators(); // Steps 2 and 3.
82 computeExplicitImmediateDominators(); // Step 4.
83 }
93a37866 84
ed1e77d3
A
85 BasicBlock* immediateDominator(BasicBlock* block)
86 {
87 return m_data[block].dom;
88 }
89
90private:
91 void computeDepthFirstPreNumbering()
92 {
93 // Use a block worklist that also tracks the index inside the successor list. This is
94 // necessary for ensuring that we don't attempt to visit a successor until the previous
95 // successors that we had visited are fully processed. This ends up being revealed in the
96 // output of this method because the first time we see an edge to a block, we set the
97 // block's parent. So, if we have:
98 //
99 // A -> B
100 // A -> C
101 // B -> C
102 //
103 // And we're processing A, then we want to ensure that if we see A->B first (and hence set
104 // B's prenumber before we set C's) then we also end up setting C's parent to B by virtue
105 // of not noticing A->C until we're done processing B.
106
107 ExtendedBlockWorklist<unsigned> worklist;
108 worklist.push(m_graph.block(0), 0);
109
110 while (BlockWith<unsigned> item = worklist.pop()) {
111 BasicBlock* block = item.block;
112 unsigned successorIndex = item.data;
113
114 // We initially push with successorIndex = 0 regardless of whether or not we have any
115 // successors. This is so that we can assign our prenumber. Subsequently we get pushed
116 // with higher successorIndex values, but only if they are in range.
117 ASSERT(!successorIndex || successorIndex < block->numSuccessors());
118
119 if (!successorIndex) {
120 m_data[block].semiNumber = m_blockByPreNumber.size();
121 m_blockByPreNumber.append(block);
122 }
123
124 if (successorIndex < block->numSuccessors()) {
125 unsigned nextSuccessorIndex = successorIndex + 1;
126 if (nextSuccessorIndex < block->numSuccessors())
127 worklist.forcePush(block, nextSuccessorIndex);
128
129 BasicBlock* successorBlock = block->successor(successorIndex);
130 if (worklist.push(successorBlock, 0))
131 m_data[successorBlock].parent = block;
132 }
133 }
134 }
93a37866 135
ed1e77d3
A
136 void computeSemiDominatorsAndImplicitImmediateDominators()
137 {
138 for (unsigned currentPreNumber = m_blockByPreNumber.size(); currentPreNumber-- > 1;) {
139 BasicBlock* block = m_blockByPreNumber[currentPreNumber];
140 BlockData& blockData = m_data[block];
141
142 // Step 2:
143 for (BasicBlock* predecessorBlock : block->predecessors) {
144 BasicBlock* intermediateBlock = eval(predecessorBlock);
145 blockData.semiNumber = std::min(
146 m_data[intermediateBlock].semiNumber, blockData.semiNumber);
147 }
148 unsigned bucketPreNumber = blockData.semiNumber;
149 ASSERT(bucketPreNumber <= currentPreNumber);
150 m_data[m_blockByPreNumber[bucketPreNumber]].bucket.append(block);
151 link(blockData.parent, block);
152
153 // Step 3:
154 for (BasicBlock* semiDominee : m_data[blockData.parent].bucket) {
155 BasicBlock* possibleDominator = eval(semiDominee);
156 BlockData& semiDomineeData = m_data[semiDominee];
157 ASSERT(m_blockByPreNumber[semiDomineeData.semiNumber] == blockData.parent);
158 BlockData& possibleDominatorData = m_data[possibleDominator];
159 if (possibleDominatorData.semiNumber < semiDomineeData.semiNumber)
160 semiDomineeData.dom = possibleDominator;
161 else
162 semiDomineeData.dom = blockData.parent;
163 }
164 m_data[blockData.parent].bucket.clear();
165 }
166 }
167
168 void computeExplicitImmediateDominators()
169 {
170 for (unsigned currentPreNumber = 1; currentPreNumber < m_blockByPreNumber.size(); ++currentPreNumber) {
171 BasicBlock* block = m_blockByPreNumber[currentPreNumber];
172 BlockData& blockData = m_data[block];
173
174 if (blockData.dom != m_blockByPreNumber[blockData.semiNumber])
175 blockData.dom = m_data[blockData.dom].dom;
176 }
177 }
178
179 void link(BasicBlock* from, BasicBlock* to)
180 {
181 m_data[to].ancestor = from;
182 }
183
184 BasicBlock* eval(BasicBlock* block)
185 {
186 if (!m_data[block].ancestor)
187 return block;
188
189 compress(block);
190 return m_data[block].label;
191 }
192
193 void compress(BasicBlock* initialBlock)
194 {
195 // This was meant to be a recursive function, but we don't like recursion because we don't
196 // want to blow the stack. The original function will call compress() recursively on the
197 // ancestor of anything that has an ancestor. So, we populate our worklist with the
198 // recursive ancestors of initialBlock. Then we process the list starting from the block
199 // that is furthest up the ancestor chain.
200
201 BasicBlock* ancestor = m_data[initialBlock].ancestor;
202 ASSERT(ancestor);
203 if (!m_data[ancestor].ancestor)
204 return;
205
206 Vector<BasicBlock*, 16> stack;
207 for (BasicBlock* block = initialBlock; block; block = m_data[block].ancestor)
208 stack.append(block);
209
210 // We only care about blocks that have an ancestor that has an ancestor. The last two
211 // elements in the stack won't satisfy this property.
212 ASSERT(stack.size() >= 2);
213 ASSERT(!m_data[stack[stack.size() - 1]].ancestor);
214 ASSERT(!m_data[m_data[stack[stack.size() - 2]].ancestor].ancestor);
215
216 for (unsigned i = stack.size() - 2; i--;) {
217 BasicBlock* block = stack[i];
218 BasicBlock*& labelOfBlock = m_data[block].label;
219 BasicBlock*& ancestorOfBlock = m_data[block].ancestor;
220 ASSERT(ancestorOfBlock);
221 ASSERT(m_data[ancestorOfBlock].ancestor);
222
223 BasicBlock* labelOfAncestorOfBlock = m_data[ancestorOfBlock].label;
224
225 if (m_data[labelOfAncestorOfBlock].semiNumber < m_data[labelOfBlock].semiNumber)
226 labelOfBlock = labelOfAncestorOfBlock;
227 ancestorOfBlock = m_data[ancestorOfBlock].ancestor;
228 }
93a37866 229 }
81345200 230
ed1e77d3
A
231 struct BlockData {
232 BlockData()
233 : parent(nullptr)
234 , preNumber(UINT_MAX)
235 , semiNumber(UINT_MAX)
236 , ancestor(nullptr)
237 , label(nullptr)
238 , dom(nullptr)
239 {
240 }
241
242 BasicBlock* parent;
243 unsigned preNumber;
244 unsigned semiNumber;
245 BasicBlock* ancestor;
246 BasicBlock* label;
247 Vector<BasicBlock*> bucket;
248 BasicBlock* dom;
249 };
250
251 Graph& m_graph;
252 BlockMap<BlockData> m_data;
253 Vector<BasicBlock*> m_blockByPreNumber;
254};
81345200 255
ed1e77d3
A
256struct ValidationContext {
257 ValidationContext(Graph& graph, Dominators& dominators)
258 : graph(graph)
259 , dominators(dominators)
260 {
93a37866
A
261 }
262
ed1e77d3
A
263 void reportError(BasicBlock* from, BasicBlock* to, const char* message)
264 {
265 Error error;
266 error.from = from;
267 error.to = to;
268 error.message = message;
269 errors.append(error);
93a37866 270 }
ed1e77d3
A
271
272 void handleErrors()
273 {
274 if (errors.isEmpty())
275 return;
276
277 startCrashing();
278 dataLog("DFG DOMINATOR VALIDATION FAILED:\n");
279 dataLog("\n");
280 dataLog("For block domination relationships:\n");
281 for (unsigned i = 0; i < errors.size(); ++i) {
282 dataLog(
283 " ", pointerDump(errors[i].from), " -> ", pointerDump(errors[i].to),
284 " (", errors[i].message, ")\n");
285 }
286 dataLog("\n");
287 dataLog("Control flow graph:\n");
288 for (BlockIndex blockIndex = 0; blockIndex < graph.numBlocks(); ++blockIndex) {
289 BasicBlock* block = graph.block(blockIndex);
290 if (!block)
291 continue;
292 dataLog(" Block #", blockIndex, ": successors = [");
293 CommaPrinter comma;
294 for (unsigned i = 0; i < block->numSuccessors(); ++i)
295 dataLog(comma, *block->successor(i));
296 dataLog("], predecessors = [");
297 comma = CommaPrinter();
298 for (unsigned i = 0; i < block->predecessors.size(); ++i)
299 dataLog(comma, *block->predecessors[i]);
300 dataLog("]\n");
301 }
302 dataLog("\n");
303 dataLog("Lengauer-Tarjan Dominators:\n");
304 dataLog(dominators);
305 dataLog("\n");
306 dataLog("Naive Dominators:\n");
307 naiveDominators.dump(graph, WTF::dataFile());
308 dataLog("\n");
309 dataLog("Graph at time of failure:\n");
310 graph.dump();
311 dataLog("\n");
312 dataLog("DFG DOMINATOR VALIDATION FAILIED!\n");
313 CRASH();
314 }
315
316 Graph& graph;
317 Dominators& dominators;
318 NaiveDominators naiveDominators;
319
320 struct Error {
321 BasicBlock* from;
322 BasicBlock* to;
323 const char* message;
324 };
325
326 Vector<Error> errors;
327};
328
329} // anonymous namespace
81345200 330
ed1e77d3
A
331void Dominators::compute(Graph& graph)
332{
333 LengauerTarjan lengauerTarjan(graph);
334 lengauerTarjan.compute();
81345200 335
ed1e77d3
A
336 m_data = BlockMap<BlockData>(graph);
337
338 // From here we want to build a spanning tree with both upward and downward links and we want
339 // to do a search over this tree to compute pre and post numbers that can be used for dominance
340 // tests.
341
342 for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
343 BasicBlock* block = graph.block(blockIndex);
344 if (!block)
345 continue;
346
347 BasicBlock* idomBlock = lengauerTarjan.immediateDominator(block);
348 m_data[block].idomParent = idomBlock;
349 if (idomBlock)
350 m_data[idomBlock].idomKids.append(block);
351 }
352
353 unsigned nextPreNumber = 0;
354 unsigned nextPostNumber = 0;
355
356 // Plain stack-based worklist because we are guaranteed to see each block exactly once anyway.
357 Vector<BlockWithOrder> worklist;
358 worklist.append(BlockWithOrder(graph.block(0), PreOrder));
359 while (!worklist.isEmpty()) {
360 BlockWithOrder item = worklist.takeLast();
361 switch (item.order) {
362 case PreOrder:
363 m_data[item.block].preNumber = nextPreNumber++;
364 worklist.append(BlockWithOrder(item.block, PostOrder));
365 for (BasicBlock* kid : m_data[item.block].idomKids)
366 worklist.append(BlockWithOrder(kid, PreOrder));
93a37866 367 break;
ed1e77d3
A
368 case PostOrder:
369 m_data[item.block].postNumber = nextPostNumber++;
370 break;
371 }
372 }
373
374 if (validationEnabled()) {
375 // Check our dominator calculation:
376 // 1) Check that our range-based ancestry test is the same as a naive ancestry test.
377 // 2) Check that our notion of who dominates whom is identical to a naive (not
378 // Lengauer-Tarjan) dominator calculation.
379
380 ValidationContext context(graph, *this);
381 context.naiveDominators.compute(graph);
382
383 for (BlockIndex fromBlockIndex = graph.numBlocks(); fromBlockIndex--;) {
384 BasicBlock* fromBlock = graph.block(fromBlockIndex);
385 if (!fromBlock || m_data[fromBlock].preNumber == UINT_MAX)
386 continue;
387 for (BlockIndex toBlockIndex = graph.numBlocks(); toBlockIndex--;) {
388 BasicBlock* toBlock = graph.block(toBlockIndex);
389 if (!toBlock || m_data[toBlock].preNumber == UINT_MAX)
390 continue;
391
392 if (dominates(fromBlock, toBlock) != naiveDominates(fromBlock, toBlock))
393 context.reportError(fromBlock, toBlock, "Range-based domination check is broken");
394 if (dominates(fromBlock, toBlock) != context.naiveDominators.dominates(fromBlock, toBlock))
395 context.reportError(fromBlock, toBlock, "Lengauer-Tarjan domination is broken");
396 }
397 }
398
399 context.handleErrors();
400 }
401}
81345200 402
ed1e77d3
A
403BlockSet Dominators::strictDominatorsOf(BasicBlock* to) const
404{
405 BlockSet result;
406 forAllStrictDominatorsOf(to, BlockAdder(result));
407 return result;
93a37866
A
408}
409
ed1e77d3 410BlockSet Dominators::dominatorsOf(BasicBlock* to) const
93a37866 411{
ed1e77d3
A
412 BlockSet result;
413 forAllDominatorsOf(to, BlockAdder(result));
414 return result;
415}
81345200 416
ed1e77d3
A
417BlockSet Dominators::blocksStrictlyDominatedBy(BasicBlock* from) const
418{
419 BlockSet result;
420 forAllBlocksStrictlyDominatedBy(from, BlockAdder(result));
421 return result;
422}
81345200 423
ed1e77d3
A
424BlockSet Dominators::blocksDominatedBy(BasicBlock* from) const
425{
426 BlockSet result;
427 forAllBlocksDominatedBy(from, BlockAdder(result));
428 return result;
429}
81345200 430
ed1e77d3
A
431BlockSet Dominators::dominanceFrontierOf(BasicBlock* from) const
432{
433 BlockSet result;
434 forAllBlocksInDominanceFrontierOfImpl(from, BlockAdder(result));
435 return result;
436}
81345200 437
ed1e77d3
A
438BlockSet Dominators::iteratedDominanceFrontierOf(const BlockList& from) const
439{
440 BlockSet result;
441 forAllBlocksInIteratedDominanceFrontierOfImpl(from, BlockAdder(result));
442 return result;
81345200
A
443}
444
ed1e77d3 445bool Dominators::naiveDominates(BasicBlock* from, BasicBlock* to) const
81345200 446{
ed1e77d3
A
447 for (BasicBlock* block = to; block; block = m_data[block].idomParent) {
448 if (block == from)
449 return true;
450 }
451 return false;
452}
453
454void Dominators::dump(PrintStream& out) const
455{
456 if (!isValid()) {
457 out.print(" Not Valid.\n");
458 return;
459 }
460
461 for (BlockIndex blockIndex = 0; blockIndex < m_data.size(); ++blockIndex) {
462 if (m_data[blockIndex].preNumber == UINT_MAX)
81345200 463 continue;
ed1e77d3
A
464
465 out.print(" Block #", blockIndex, ": idom = ", pointerDump(m_data[blockIndex].idomParent), ", idomKids = [");
466 CommaPrinter comma;
467 for (unsigned i = 0; i < m_data[blockIndex].idomKids.size(); ++i)
468 out.print(comma, *m_data[blockIndex].idomKids[i]);
469 out.print("], pre/post = ", m_data[blockIndex].preNumber, "/", m_data[blockIndex].postNumber, "\n");
81345200 470 }
93a37866
A
471}
472
473} } // namespace JSC::DFG
474
475#endif // ENABLE(DFG_JIT)
476