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