8baa03c14e126a8a4faf56430ac8e7fb07c20d82
[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::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::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->hasTypedArrayType())
250         out.print(comma, node->typedArrayType());
251     if (node->hasPhi())
252         out.print(comma, "^", node->phi()->index());
253     if (node->hasExecutionCounter())
254         out.print(comma, RawPointer(node->executionCounter()));
255     if (op == JSConstant) {
256         out.print(comma, "$", node->constantNumber());
257         JSValue value = valueOfJSConstant(node);
258         out.print(" = ", inContext(value, context));
259     }
260     if (op == WeakJSConstant)
261         out.print(comma, RawPointer(node->weakConstant()), " (", inContext(*node->weakConstant()->structure(), context), ")");
262     if (node->isBranch() || node->isJump())
263         out.print(comma, "T:", *node->takenBlock());
264     if (node->isBranch())
265         out.print(comma, "F:", *node->notTakenBlock());
266     if (node->isSwitch()) {
267         SwitchData* data = node->switchData();
268         out.print(comma, data->kind);
269         for (unsigned i = 0; i < data->cases.size(); ++i)
270             out.print(comma, inContext(data->cases[i].value, context), ":", *data->cases[i].target);
271         out.print(comma, "default:", *data->fallThrough);
272     }
273     ClobberSet reads;
274     ClobberSet writes;
275     addReadsAndWrites(*this, node, reads, writes);
276     if (!reads.isEmpty())
277         out.print(comma, "R:", sortedListDump(reads.direct(), ","));
278     if (!writes.isEmpty())
279         out.print(comma, "W:", sortedListDump(writes.direct(), ","));
280     out.print(comma, "bc#", node->codeOrigin.bytecodeIndex);
281     
282     out.print(")");
283
284     if (!skipped) {
285         if (node->hasVariableAccessData(*this))
286             out.print("  predicting ", SpeculationDump(node->variableAccessData()->prediction()), node->variableAccessData()->shouldUseDoubleFormat() ? ", forcing double" : "");
287         else if (node->hasHeapPrediction())
288             out.print("  predicting ", SpeculationDump(node->getHeapPrediction()));
289     }
290     
291     out.print("\n");
292 }
293
294 void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
295 {
296     out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->codeOrigin, context), "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
297     out.print(prefix, "  Predecessors:");
298     for (size_t i = 0; i < block->predecessors.size(); ++i)
299         out.print(" ", *block->predecessors[i]);
300     out.print("\n");
301     if (m_dominators.isValid()) {
302         out.print(prefix, "  Dominated by:");
303         for (size_t i = 0; i < m_blocks.size(); ++i) {
304             if (!m_dominators.dominates(i, block->index))
305                 continue;
306             out.print(" #", i);
307         }
308         out.print("\n");
309         out.print(prefix, "  Dominates:");
310         for (size_t i = 0; i < m_blocks.size(); ++i) {
311             if (!m_dominators.dominates(block->index, i))
312                 continue;
313             out.print(" #", i);
314         }
315         out.print("\n");
316     }
317     if (m_naturalLoops.isValid()) {
318         if (const NaturalLoop* loop = m_naturalLoops.headerOf(block)) {
319             out.print(prefix, "  Loop header, contains:");
320             Vector<BlockIndex> sortedBlockList;
321             for (unsigned i = 0; i < loop->size(); ++i)
322                 sortedBlockList.append(loop->at(i)->index);
323             std::sort(sortedBlockList.begin(), sortedBlockList.end());
324             for (unsigned i = 0; i < sortedBlockList.size(); ++i)
325                 out.print(" #", sortedBlockList[i]);
326             out.print("\n");
327         }
328         
329         Vector<const NaturalLoop*> containingLoops =
330             m_naturalLoops.loopsOf(block);
331         if (!containingLoops.isEmpty()) {
332             out.print(prefix, "  Containing loop headers:");
333             for (unsigned i = 0; i < containingLoops.size(); ++i)
334                 out.print(" ", *containingLoops[i]->header());
335             out.print("\n");
336         }
337     }
338     if (!block->phis.isEmpty()) {
339         out.print(prefix, "  Phi Nodes:");
340         for (size_t i = 0; i < block->phis.size(); ++i) {
341             Node* phiNode = block->phis[i];
342             if (!phiNode->shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly)
343                 continue;
344             out.print(" @", phiNode->index(), "<", phiNode->refCount(), ">->(");
345             if (phiNode->child1()) {
346                 out.print("@", phiNode->child1()->index());
347                 if (phiNode->child2()) {
348                     out.print(", @", phiNode->child2()->index());
349                     if (phiNode->child3())
350                         out.print(", @", phiNode->child3()->index());
351                 }
352             }
353             out.print(")", i + 1 < block->phis.size() ? "," : "");
354         }
355         out.print("\n");
356     }
357 }
358
359 void Graph::dump(PrintStream& out, DumpContext* context)
360 {
361     DumpContext myContext;
362     if (!context)
363         context = &myContext;
364     
365     dataLog("\n");
366     dataLog("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n");
367     dataLog("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
368     dataLog("\n");
369     
370     Node* lastNode = 0;
371     for (size_t b = 0; b < m_blocks.size(); ++b) {
372         BasicBlock* block = m_blocks[b].get();
373         if (!block)
374             continue;
375         dumpBlockHeader(out, "", block, DumpAllPhis, context);
376         switch (m_form) {
377         case LoadStore:
378         case ThreadedCPS: {
379             out.print("  vars before: ");
380             if (block->cfaHasVisited)
381                 out.print(inContext(block->valuesAtHead, context));
382             else
383                 out.print("<empty>");
384             out.print("\n");
385             out.print("  var links: ", block->variablesAtHead, "\n");
386             break;
387         }
388             
389         case SSA: {
390             RELEASE_ASSERT(block->ssa);
391             out.print("  Flush format: ", block->ssa->flushFormatAtHead, "\n");
392             out.print("  Availability: ", block->ssa->availabilityAtHead, "\n");
393             out.print("  Live: ", nodeListDump(block->ssa->liveAtHead), "\n");
394             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtHead, context), "\n");
395             break;
396         } }
397         for (size_t i = 0; i < block->size(); ++i) {
398             dumpCodeOrigin(out, "", lastNode, block->at(i), context);
399             dump(out, "", block->at(i), context);
400             lastNode = block->at(i);
401         }
402         switch (m_form) {
403         case LoadStore:
404         case ThreadedCPS: {
405             out.print("  vars after: ");
406             if (block->cfaHasVisited)
407                 out.print(inContext(block->valuesAtTail, context));
408             else
409                 out.print("<empty>");
410             out.print("\n");
411             out.print("  var links: ", block->variablesAtTail, "\n");
412             break;
413         }
414             
415         case SSA: {
416             RELEASE_ASSERT(block->ssa);
417             out.print("  Flush format: ", block->ssa->flushFormatAtTail, "\n");
418             out.print("  Availability: ", block->ssa->availabilityAtTail, "\n");
419             out.print("  Live: ", nodeListDump(block->ssa->liveAtTail), "\n");
420             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtTail, context), "\n");
421             break;
422         } }
423         dataLog("\n");
424     }
425     
426     if (!myContext.isEmpty()) {
427         myContext.dump(WTF::dataFile());
428         dataLog("\n");
429     }
430 }
431
432 void Graph::dethread()
433 {
434     if (m_form == LoadStore || m_form == SSA)
435         return;
436     
437     if (logCompilationChanges())
438         dataLog("Dethreading DFG graph.\n");
439     
440     SamplingRegion samplingRegion("DFG Dethreading");
441     
442     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
443         BasicBlock* block = m_blocks[blockIndex].get();
444         if (!block)
445             continue;
446         for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
447             Node* phi = block->phis[phiIndex];
448             phi->children.reset();
449         }
450     }
451     
452     m_form = LoadStore;
453 }
454
455 void Graph::handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock* block, BasicBlock* successor)
456 {
457     if (!successor->isReachable) {
458         successor->isReachable = true;
459         worklist.append(successor);
460     }
461     
462     successor->predecessors.append(block);
463 }
464
465 void Graph::determineReachability()
466 {
467     Vector<BasicBlock*, 16> worklist;
468     worklist.append(block(0));
469     block(0)->isReachable = true;
470     while (!worklist.isEmpty()) {
471         BasicBlock* block = worklist.takeLast();
472         for (unsigned i = block->numSuccessors(); i--;)
473             handleSuccessor(worklist, block, block->successor(i));
474     }
475 }
476
477 void Graph::resetReachability()
478 {
479     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
480         BasicBlock* block = m_blocks[blockIndex].get();
481         if (!block)
482             continue;
483         block->isReachable = false;
484         block->predecessors.clear();
485     }
486     
487     determineReachability();
488 }
489
490 void Graph::resetExitStates()
491 {
492     for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) {
493         BasicBlock* block = m_blocks[blockIndex].get();
494         if (!block)
495             continue;
496         for (unsigned indexInBlock = block->size(); indexInBlock--;)
497             block->at(indexInBlock)->setCanExit(true);
498     }
499 }
500
501 void Graph::invalidateCFG()
502 {
503     m_dominators.invalidate();
504     m_naturalLoops.invalidate();
505 }
506
507 void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal)
508 {
509     if (variableAccessData->isCaptured()) {
510         // Let CSE worry about this one.
511         return;
512     }
513     for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
514         Node* node = block[indexInBlock];
515         bool shouldContinue = true;
516         switch (node->op()) {
517         case SetLocal: {
518             if (node->local() == variableAccessData->local())
519                 shouldContinue = false;
520             break;
521         }
522                 
523         case GetLocal: {
524             if (node->variableAccessData() != variableAccessData)
525                 continue;
526             substitute(block, indexInBlock, node, newGetLocal);
527             Node* oldTailNode = block.variablesAtTail.operand(variableAccessData->local());
528             if (oldTailNode == node)
529                 block.variablesAtTail.operand(variableAccessData->local()) = newGetLocal;
530             shouldContinue = false;
531             break;
532         }
533                 
534         default:
535             break;
536         }
537         if (!shouldContinue)
538             break;
539     }
540 }
541
542 void Graph::addForDepthFirstSort(Vector<BasicBlock*>& result, Vector<BasicBlock*, 16>& worklist, HashSet<BasicBlock*>& seen, BasicBlock* block)
543 {
544     if (seen.contains(block))
545         return;
546     
547     result.append(block);
548     worklist.append(block);
549     seen.add(block);
550 }
551
552 void Graph::getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result)
553 {
554     Vector<BasicBlock*, 16> worklist;
555     HashSet<BasicBlock*> seen;
556     addForDepthFirstSort(result, worklist, seen, block(0));
557     while (!worklist.isEmpty()) {
558         BasicBlock* block = worklist.takeLast();
559         for (unsigned i = block->numSuccessors(); i--;)
560             addForDepthFirstSort(result, worklist, seen, block->successor(i));
561     }
562 }
563
564 void Graph::clearReplacements()
565 {
566     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
567         BasicBlock* block = m_blocks[blockIndex].get();
568         if (!block)
569             continue;
570         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
571             block->phis[phiIndex]->misc.replacement = 0;
572         for (unsigned nodeIndex = block->size(); nodeIndex--;)
573             block->at(nodeIndex)->misc.replacement = 0;
574     }
575 }
576
577 void Graph::initializeNodeOwners()
578 {
579     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
580         BasicBlock* block = m_blocks[blockIndex].get();
581         if (!block)
582             continue;
583         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
584             block->phis[phiIndex]->misc.owner = block;
585         for (unsigned nodeIndex = block->size(); nodeIndex--;)
586             block->at(nodeIndex)->misc.owner = block;
587     }
588 }
589     
590 } } // namespace JSC::DFG
591
592 #endif