Unreviewed, rolling out r156474.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGGraph.cpp
1 /*
2  * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
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 "DFGGraph.h"
28
29 #include "CodeBlock.h"
30 #include "CodeBlockWithJITType.h"
31 #include "DFGClobberSet.h"
32 #include "DFGJITCode.h"
33 #include "DFGVariableAccessDataDump.h"
34 #include "FunctionExecutableDump.h"
35 #include "OperandsInlines.h"
36 #include "Operations.h"
37 #include <wtf/CommaPrinter.h>
38 #include <wtf/ListDump.h>
39
40 #if ENABLE(DFG_JIT)
41
42 namespace JSC { namespace DFG {
43
44 // Creates an array of stringized names.
45 static const char* dfgOpNames[] = {
46 #define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
47     FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
48 #undef STRINGIZE_DFG_OP_ENUM
49 };
50
51 Graph::Graph(VM& vm, Plan& plan, LongLivedState& longLivedState)
52     : m_vm(vm)
53     , m_plan(plan)
54     , m_codeBlock(m_plan.codeBlock.get())
55     , m_profiledBlock(m_codeBlock->alternative())
56     , m_allocator(longLivedState.m_allocator)
57     , m_inlineCallFrames(adoptPtr(new InlineCallFrameSet()))
58     , m_hasArguments(false)
59     , m_fixpointState(BeforeFixpoint)
60     , m_form(LoadStore)
61     , m_unificationState(LocallyUnified)
62     , m_refCountState(EverythingIsLive)
63 {
64     ASSERT(m_profiledBlock);
65 }
66
67 Graph::~Graph()
68 {
69     m_allocator.freeAll();
70 }
71
72 const char *Graph::opName(NodeType op)
73 {
74     return dfgOpNames[op];
75 }
76
77 static void printWhiteSpace(PrintStream& out, unsigned amount)
78 {
79     while (amount-- > 0)
80         out.print(" ");
81 }
82
83 bool Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, Node* previousNode, Node* currentNode, DumpContext* context)
84 {
85     if (!previousNode)
86         return false;
87     
88     if (previousNode->codeOrigin.inlineCallFrame == currentNode->codeOrigin.inlineCallFrame)
89         return false;
90     
91     Vector<CodeOrigin> previousInlineStack = previousNode->codeOrigin.inlineStack();
92     Vector<CodeOrigin> currentInlineStack = currentNode->codeOrigin.inlineStack();
93     unsigned commonSize = std::min(previousInlineStack.size(), currentInlineStack.size());
94     unsigned indexOfDivergence = commonSize;
95     for (unsigned i = 0; i < commonSize; ++i) {
96         if (previousInlineStack[i].inlineCallFrame != currentInlineStack[i].inlineCallFrame) {
97             indexOfDivergence = i;
98             break;
99         }
100     }
101     
102     bool hasPrinted = false;
103     
104     // Print the pops.
105     for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
106         out.print(prefix);
107         printWhiteSpace(out, i * 2);
108         out.print("<-- ", inContext(*previousInlineStack[i].inlineCallFrame, context), "\n");
109         hasPrinted = true;
110     }
111     
112     // Print the pushes.
113     for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) {
114         out.print(prefix);
115         printWhiteSpace(out, i * 2);
116         out.print("--> ", inContext(*currentInlineStack[i].inlineCallFrame, context), "\n");
117         hasPrinted = true;
118     }
119     
120     return hasPrinted;
121 }
122
123 int Graph::amountOfNodeWhiteSpace(Node* node)
124 {
125     return (node->codeOrigin.inlineDepth() - 1) * 2;
126 }
127
128 void Graph::printNodeWhiteSpace(PrintStream& out, Node* node)
129 {
130     printWhiteSpace(out, amountOfNodeWhiteSpace(node));
131 }
132
133 void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* context)
134 {
135     NodeType op = node->op();
136
137     unsigned refCount = node->refCount();
138     bool skipped = !refCount;
139     bool mustGenerate = node->mustGenerate();
140     if (mustGenerate)
141         --refCount;
142
143     out.print(prefix);
144     printNodeWhiteSpace(out, node);
145
146     // Example/explanation of dataflow dump output
147     //
148     //   14:   <!2:7>  GetByVal(@3, @13)
149     //   ^1     ^2 ^3     ^4       ^5
150     //
151     // (1) The nodeIndex of this operation.
152     // (2) The reference count. The number printed is the 'real' count,
153     //     not including the 'mustGenerate' ref. If the node is
154     //     'mustGenerate' then the count it prefixed with '!'.
155     // (3) The virtual register slot assigned to this node.
156     // (4) The name of the operation.
157     // (5) The arguments to the operation. The may be of the form:
158     //         @#   - a NodeIndex referencing a prior node in the graph.
159     //         arg# - an argument number.
160     //         $#   - the index in the CodeBlock of a constant { for numeric constants the value is displayed | for integers, in both decimal and hex }.
161     //         id#  - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
162     //         var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
163     out.printf("% 4d:%s<%c%u:", (int)node->index(), skipped ? "  skipped  " : "           ", mustGenerate ? '!' : ' ', refCount);
164     if (node->hasResult() && !skipped && node->hasVirtualRegister())
165         out.print(node->virtualRegister());
166     else
167         out.print("-");
168     out.print(">\t", opName(op), "(");
169     CommaPrinter comma;
170     if (node->flags() & NodeHasVarArgs) {
171         for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
172             if (!m_varArgChildren[childIdx])
173                 continue;
174             out.print(comma, m_varArgChildren[childIdx]);
175         }
176     } else {
177         if (!!node->child1() || !!node->child2() || !!node->child3())
178             out.print(comma, node->child1());
179         if (!!node->child2() || !!node->child3())
180             out.print(comma, node->child2());
181         if (!!node->child3())
182             out.print(comma, node->child3());
183     }
184
185     if (toCString(NodeFlagsDump(node->flags())) != "<empty>")
186         out.print(comma, NodeFlagsDump(node->flags()));
187     if (node->prediction())
188         out.print(comma, SpeculationDump(node->prediction()));
189     if (node->hasArrayMode())
190         out.print(comma, node->arrayMode());
191     if (node->hasVarNumber())
192         out.print(comma, node->varNumber());
193     if (node->hasRegisterPointer())
194         out.print(comma, "global", globalObjectFor(node->codeOrigin)->findRegisterIndex(node->registerPointer()), "(", RawPointer(node->registerPointer()), ")");
195     if (node->hasIdentifier())
196         out.print(comma, "id", node->identifierNumber(), "{", identifiers()[node->identifierNumber()], "}");
197     if (node->hasStructureSet())
198         out.print(comma, inContext(node->structureSet(), context));
199     if (node->hasStructure())
200         out.print(comma, inContext(*node->structure(), context));
201     if (node->hasStructureTransitionData())
202         out.print(comma, inContext(*node->structureTransitionData().previousStructure, context), " -> ", inContext(*node->structureTransitionData().newStructure, context));
203     if (node->hasFunction()) {
204         out.print(comma, "function(", RawPointer(node->function()), ", ");
205         if (node->function()->inherits(JSFunction::info())) {
206             JSFunction* function = jsCast<JSFunction*>(node->function());
207             if (function->isHostFunction())
208                 out.print("<host function>");
209             else
210                 out.print(FunctionExecutableDump(function->jsExecutable()));
211         } else
212             out.print("<not JSFunction>");
213         out.print(")");
214     }
215     if (node->hasExecutable()) {
216         if (node->executable()->inherits(FunctionExecutable::info()))
217             out.print(comma, "executable(", FunctionExecutableDump(jsCast<FunctionExecutable*>(node->executable())), ")");
218         else
219             out.print(comma, "executable(not function: ", RawPointer(node->executable()), ")");
220     }
221     if (node->hasFunctionDeclIndex()) {
222         FunctionExecutable* executable = m_codeBlock->functionDecl(node->functionDeclIndex());
223         out.print(comma, FunctionExecutableDump(executable));
224     }
225     if (node->hasFunctionExprIndex()) {
226         FunctionExecutable* executable = m_codeBlock->functionExpr(node->functionExprIndex());
227         out.print(comma, FunctionExecutableDump(executable));
228     }
229     if (node->hasStorageAccessData()) {
230         StorageAccessData& storageAccessData = m_storageAccessData[node->storageAccessDataIndex()];
231         out.print(comma, "id", storageAccessData.identifierNumber, "{", identifiers()[storageAccessData.identifierNumber], "}");
232         out.print(", ", static_cast<ptrdiff_t>(storageAccessData.offset));
233     }
234     ASSERT(node->hasVariableAccessData(*this) == node->hasLocal(*this));
235     if (node->hasVariableAccessData(*this)) {
236         VariableAccessData* variableAccessData = node->variableAccessData();
237         int operand = variableAccessData->operand();
238         if (operandIsArgument(operand))
239             out.print(comma, "arg", operandToArgument(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")");
240         else
241             out.print(comma, "loc", operandToLocal(operand), "(", VariableAccessDataDump(*this, variableAccessData), ")");
242     }
243     if (node->hasUnlinkedLocal()) {
244         int operand = node->unlinkedLocal();
245         if (operandIsArgument(operand))
246             out.print(comma, "arg", operandToArgument(operand));
247         else
248             out.print(comma, "loc", operandToLocal(operand));
249     }
250     if (node->hasConstantBuffer()) {
251         out.print(comma);
252         out.print(node->startConstant(), ":[");
253         CommaPrinter anotherComma;
254         for (unsigned i = 0; i < node->numConstants(); ++i)
255             out.print(anotherComma, inContext(m_codeBlock->constantBuffer(node->startConstant())[i], context));
256         out.print("]");
257     }
258     if (node->hasIndexingType())
259         out.print(comma, IndexingTypeDump(node->indexingType()));
260     if (node->hasTypedArrayType())
261         out.print(comma, node->typedArrayType());
262     if (node->hasPhi())
263         out.print(comma, "^", node->phi()->index());
264     if (node->hasExecutionCounter())
265         out.print(comma, RawPointer(node->executionCounter()));
266     if (op == JSConstant) {
267         out.print(comma, "$", node->constantNumber());
268         JSValue value = valueOfJSConstant(node);
269         out.print(" = ", inContext(value, context));
270     }
271     if (op == WeakJSConstant)
272         out.print(comma, RawPointer(node->weakConstant()), " (", inContext(*node->weakConstant()->structure(), context), ")");
273     if (node->isBranch() || node->isJump())
274         out.print(comma, "T:", *node->takenBlock());
275     if (node->isBranch())
276         out.print(comma, "F:", *node->notTakenBlock());
277     if (node->isSwitch()) {
278         SwitchData* data = node->switchData();
279         out.print(comma, data->kind);
280         for (unsigned i = 0; i < data->cases.size(); ++i)
281             out.print(comma, inContext(data->cases[i].value, context), ":", *data->cases[i].target);
282         out.print(comma, "default:", *data->fallThrough);
283     }
284     ClobberSet reads;
285     ClobberSet writes;
286     addReadsAndWrites(*this, node, reads, writes);
287     if (!reads.isEmpty())
288         out.print(comma, "R:", sortedListDump(reads.direct(), ","));
289     if (!writes.isEmpty())
290         out.print(comma, "W:", sortedListDump(writes.direct(), ","));
291     out.print(comma, "bc#", node->codeOrigin.bytecodeIndex);
292     
293     out.print(")");
294
295     if (!skipped) {
296         if (node->hasVariableAccessData(*this))
297             out.print("  predicting ", SpeculationDump(node->variableAccessData()->prediction()));
298         else if (node->hasHeapPrediction())
299             out.print("  predicting ", SpeculationDump(node->getHeapPrediction()));
300     }
301     
302     out.print("\n");
303 }
304
305 void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
306 {
307     out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->codeOrigin, context), "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
308     out.print(prefix, "  Predecessors:");
309     for (size_t i = 0; i < block->predecessors.size(); ++i)
310         out.print(" ", *block->predecessors[i]);
311     out.print("\n");
312     if (m_dominators.isValid()) {
313         out.print(prefix, "  Dominated by:");
314         for (size_t i = 0; i < m_blocks.size(); ++i) {
315             if (!m_dominators.dominates(i, block->index))
316                 continue;
317             out.print(" #", i);
318         }
319         out.print("\n");
320         out.print(prefix, "  Dominates:");
321         for (size_t i = 0; i < m_blocks.size(); ++i) {
322             if (!m_dominators.dominates(block->index, i))
323                 continue;
324             out.print(" #", i);
325         }
326         out.print("\n");
327     }
328     if (m_naturalLoops.isValid()) {
329         if (const NaturalLoop* loop = m_naturalLoops.headerOf(block)) {
330             out.print(prefix, "  Loop header, contains:");
331             Vector<BlockIndex> sortedBlockList;
332             for (unsigned i = 0; i < loop->size(); ++i)
333                 sortedBlockList.append(loop->at(i)->index);
334             std::sort(sortedBlockList.begin(), sortedBlockList.end());
335             for (unsigned i = 0; i < sortedBlockList.size(); ++i)
336                 out.print(" #", sortedBlockList[i]);
337             out.print("\n");
338         }
339         
340         Vector<const NaturalLoop*> containingLoops =
341             m_naturalLoops.loopsOf(block);
342         if (!containingLoops.isEmpty()) {
343             out.print(prefix, "  Containing loop headers:");
344             for (unsigned i = 0; i < containingLoops.size(); ++i)
345                 out.print(" ", *containingLoops[i]->header());
346             out.print("\n");
347         }
348     }
349     if (!block->phis.isEmpty()) {
350         out.print(prefix, "  Phi Nodes:");
351         for (size_t i = 0; i < block->phis.size(); ++i) {
352             Node* phiNode = block->phis[i];
353             if (!phiNode->shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly)
354                 continue;
355             out.print(" @", phiNode->index(), "<", phiNode->refCount(), ">->(");
356             if (phiNode->child1()) {
357                 out.print("@", phiNode->child1()->index());
358                 if (phiNode->child2()) {
359                     out.print(", @", phiNode->child2()->index());
360                     if (phiNode->child3())
361                         out.print(", @", phiNode->child3()->index());
362                 }
363             }
364             out.print(")", i + 1 < block->phis.size() ? "," : "");
365         }
366         out.print("\n");
367     }
368 }
369
370 void Graph::dump(PrintStream& out, DumpContext* context)
371 {
372     DumpContext myContext;
373     if (!context)
374         context = &myContext;
375     
376     dataLog("\n");
377     dataLog("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n");
378     dataLog("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
379     dataLog("\n");
380     
381     Node* lastNode = 0;
382     for (size_t b = 0; b < m_blocks.size(); ++b) {
383         BasicBlock* block = m_blocks[b].get();
384         if (!block)
385             continue;
386         dumpBlockHeader(out, "", block, DumpAllPhis, context);
387         switch (m_form) {
388         case LoadStore:
389         case ThreadedCPS: {
390             out.print("  vars before: ");
391             if (block->cfaHasVisited)
392                 out.print(inContext(block->valuesAtHead, context));
393             else
394                 out.print("<empty>");
395             out.print("\n");
396             out.print("  var links: ", block->variablesAtHead, "\n");
397             break;
398         }
399             
400         case SSA: {
401             RELEASE_ASSERT(block->ssa);
402             out.print("  Flush format: ", block->ssa->flushFormatAtHead, "\n");
403             out.print("  Availability: ", block->ssa->availabilityAtHead, "\n");
404             out.print("  Live: ", nodeListDump(block->ssa->liveAtHead), "\n");
405             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtHead, context), "\n");
406             break;
407         } }
408         for (size_t i = 0; i < block->size(); ++i) {
409             dumpCodeOrigin(out, "", lastNode, block->at(i), context);
410             dump(out, "", block->at(i), context);
411             lastNode = block->at(i);
412         }
413         switch (m_form) {
414         case LoadStore:
415         case ThreadedCPS: {
416             out.print("  vars after: ");
417             if (block->cfaHasVisited)
418                 out.print(inContext(block->valuesAtTail, context));
419             else
420                 out.print("<empty>");
421             out.print("\n");
422             out.print("  var links: ", block->variablesAtTail, "\n");
423             break;
424         }
425             
426         case SSA: {
427             RELEASE_ASSERT(block->ssa);
428             out.print("  Flush format: ", block->ssa->flushFormatAtTail, "\n");
429             out.print("  Availability: ", block->ssa->availabilityAtTail, "\n");
430             out.print("  Live: ", nodeListDump(block->ssa->liveAtTail), "\n");
431             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtTail, context), "\n");
432             break;
433         } }
434         dataLog("\n");
435     }
436     
437     if (!myContext.isEmpty()) {
438         myContext.dump(WTF::dataFile());
439         dataLog("\n");
440     }
441 }
442
443 void Graph::dethread()
444 {
445     if (m_form == LoadStore || m_form == SSA)
446         return;
447     
448     if (logCompilationChanges())
449         dataLog("Dethreading DFG graph.\n");
450     
451     SamplingRegion samplingRegion("DFG Dethreading");
452     
453     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
454         BasicBlock* block = m_blocks[blockIndex].get();
455         if (!block)
456             continue;
457         for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
458             Node* phi = block->phis[phiIndex];
459             phi->children.reset();
460         }
461     }
462     
463     m_form = LoadStore;
464 }
465
466 void Graph::handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock* block, BasicBlock* successor)
467 {
468     if (!successor->isReachable) {
469         successor->isReachable = true;
470         worklist.append(successor);
471     }
472     
473     successor->predecessors.append(block);
474 }
475
476 void Graph::determineReachability()
477 {
478     Vector<BasicBlock*, 16> worklist;
479     worklist.append(block(0));
480     block(0)->isReachable = true;
481     while (!worklist.isEmpty()) {
482         BasicBlock* block = worklist.takeLast();
483         for (unsigned i = block->numSuccessors(); i--;)
484             handleSuccessor(worklist, block, block->successor(i));
485     }
486 }
487
488 void Graph::resetReachability()
489 {
490     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
491         BasicBlock* block = m_blocks[blockIndex].get();
492         if (!block)
493             continue;
494         block->isReachable = false;
495         block->predecessors.clear();
496     }
497     
498     determineReachability();
499 }
500
501 void Graph::killBlockAndItsContents(BasicBlock* block)
502 {
503     for (unsigned phiIndex = block->phis.size(); phiIndex--;)
504         m_allocator.free(block->phis[phiIndex]);
505     for (unsigned nodeIndex = block->size(); nodeIndex--;)
506         m_allocator.free(block->at(nodeIndex));
507     
508     killBlock(block);
509 }
510
511 void Graph::killUnreachableBlocks()
512 {
513     for (BlockIndex blockIndex = 0; blockIndex < numBlocks(); ++blockIndex) {
514         BasicBlock* block = this->block(blockIndex);
515         if (!block)
516             continue;
517         if (block->isReachable)
518             continue;
519         
520         killBlockAndItsContents(block);
521     }
522 }
523
524 void Graph::resetExitStates()
525 {
526     for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) {
527         BasicBlock* block = m_blocks[blockIndex].get();
528         if (!block)
529             continue;
530         for (unsigned indexInBlock = block->size(); indexInBlock--;)
531             block->at(indexInBlock)->setCanExit(true);
532     }
533 }
534
535 void Graph::invalidateCFG()
536 {
537     m_dominators.invalidate();
538     m_naturalLoops.invalidate();
539 }
540
541 void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal)
542 {
543     if (variableAccessData->isCaptured()) {
544         // Let CSE worry about this one.
545         return;
546     }
547     for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
548         Node* node = block[indexInBlock];
549         bool shouldContinue = true;
550         switch (node->op()) {
551         case SetLocal: {
552             if (node->local() == variableAccessData->local())
553                 shouldContinue = false;
554             break;
555         }
556                 
557         case GetLocal: {
558             if (node->variableAccessData() != variableAccessData)
559                 continue;
560             substitute(block, indexInBlock, node, newGetLocal);
561             Node* oldTailNode = block.variablesAtTail.operand(variableAccessData->local());
562             if (oldTailNode == node)
563                 block.variablesAtTail.operand(variableAccessData->local()) = newGetLocal;
564             shouldContinue = false;
565             break;
566         }
567                 
568         default:
569             break;
570         }
571         if (!shouldContinue)
572             break;
573     }
574 }
575
576 void Graph::addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock* block)
577 {
578     if (seen.contains(block))
579         return;
580     
581     result.append(block);
582     worklist.append(block);
583     seen.add(block);
584 }
585
586 void Graph::getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result)
587 {
588     Vector<BasicBlock*, 16> worklist;
589     HashSet<BasicBlock*> seen;
590     addForDepthFirstSort(result, worklist, seen, block(0));
591     while (!worklist.isEmpty()) {
592         BasicBlock* block = worklist.takeLast();
593         for (unsigned i = block->numSuccessors(); i--;)
594             addForDepthFirstSort(result, worklist, seen, block->successor(i));
595     }
596 }
597
598 void Graph::clearReplacements()
599 {
600     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
601         BasicBlock* block = m_blocks[blockIndex].get();
602         if (!block)
603             continue;
604         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
605             block->phis[phiIndex]->misc.replacement = 0;
606         for (unsigned nodeIndex = block->size(); nodeIndex--;)
607             block->at(nodeIndex)->misc.replacement = 0;
608     }
609 }
610
611 void Graph::initializeNodeOwners()
612 {
613     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
614         BasicBlock* block = m_blocks[blockIndex].get();
615         if (!block)
616             continue;
617         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
618             block->phis[phiIndex]->misc.owner = block;
619         for (unsigned nodeIndex = block->size(); nodeIndex--;)
620             block->at(nodeIndex)->misc.owner = block;
621     }
622 }
623     
624 } } // namespace JSC::DFG
625
626 #endif