StorageAccessData should be referenced in a sensible way
[WebKit.git] / Source / JavaScriptCore / dfg / DFGGraph.cpp
1 /*
2  * Copyright (C) 2011, 2013, 2014 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 #if ENABLE(DFG_JIT)
30
31 #include "BytecodeLivenessAnalysisInlines.h"
32 #include "CodeBlock.h"
33 #include "CodeBlockWithJITType.h"
34 #include "DFGBlockWorklist.h"
35 #include "DFGClobberSet.h"
36 #include "DFGJITCode.h"
37 #include "DFGVariableAccessDataDump.h"
38 #include "FullBytecodeLiveness.h"
39 #include "FunctionExecutableDump.h"
40 #include "JIT.h"
41 #include "JSLexicalEnvironment.h"
42 #include "MaxFrameExtentForSlowPathCall.h"
43 #include "OperandsInlines.h"
44 #include "JSCInlines.h"
45 #include "StackAlignment.h"
46 #include <wtf/CommaPrinter.h>
47 #include <wtf/ListDump.h>
48
49 namespace JSC { namespace DFG {
50
51 // Creates an array of stringized names.
52 static const char* dfgOpNames[] = {
53 #define STRINGIZE_DFG_OP_ENUM(opcode, flags) #opcode ,
54     FOR_EACH_DFG_OP(STRINGIZE_DFG_OP_ENUM)
55 #undef STRINGIZE_DFG_OP_ENUM
56 };
57
58 Graph::Graph(VM& vm, Plan& plan, LongLivedState& longLivedState)
59     : m_vm(vm)
60     , m_plan(plan)
61     , m_codeBlock(m_plan.codeBlock.get())
62     , m_profiledBlock(m_codeBlock->alternative())
63     , m_allocator(longLivedState.m_allocator)
64     , m_mustHandleValues(OperandsLike, plan.mustHandleValues)
65     , m_hasArguments(false)
66     , m_nextMachineLocal(0)
67     , m_machineCaptureStart(std::numeric_limits<int>::max())
68     , m_fixpointState(BeforeFixpoint)
69     , m_structureRegistrationState(HaveNotStartedRegistering)
70     , m_form(LoadStore)
71     , m_unificationState(LocallyUnified)
72     , m_refCountState(EverythingIsLive)
73 {
74     ASSERT(m_profiledBlock);
75     
76     for (unsigned i = m_mustHandleValues.size(); i--;)
77         m_mustHandleValues[i] = freezeFragile(plan.mustHandleValues[i]);
78 }
79
80 Graph::~Graph()
81 {
82     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
83         BasicBlock* block = this->block(blockIndex);
84         if (!block)
85             continue;
86
87         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
88             m_allocator.free(block->phis[phiIndex]);
89         for (unsigned nodeIndex = block->size(); nodeIndex--;)
90             m_allocator.free(block->at(nodeIndex));
91     }
92     m_allocator.freeAll();
93 }
94
95 const char *Graph::opName(NodeType op)
96 {
97     return dfgOpNames[op];
98 }
99
100 static void printWhiteSpace(PrintStream& out, unsigned amount)
101 {
102     while (amount-- > 0)
103         out.print(" ");
104 }
105
106 bool Graph::dumpCodeOrigin(PrintStream& out, const char* prefix, Node* previousNode, Node* currentNode, DumpContext* context)
107 {
108     if (!previousNode)
109         return false;
110     
111     if (previousNode->origin.semantic.inlineCallFrame == currentNode->origin.semantic.inlineCallFrame)
112         return false;
113     
114     Vector<CodeOrigin> previousInlineStack = previousNode->origin.semantic.inlineStack();
115     Vector<CodeOrigin> currentInlineStack = currentNode->origin.semantic.inlineStack();
116     unsigned commonSize = std::min(previousInlineStack.size(), currentInlineStack.size());
117     unsigned indexOfDivergence = commonSize;
118     for (unsigned i = 0; i < commonSize; ++i) {
119         if (previousInlineStack[i].inlineCallFrame != currentInlineStack[i].inlineCallFrame) {
120             indexOfDivergence = i;
121             break;
122         }
123     }
124     
125     bool hasPrinted = false;
126     
127     // Print the pops.
128     for (unsigned i = previousInlineStack.size(); i-- > indexOfDivergence;) {
129         out.print(prefix);
130         printWhiteSpace(out, i * 2);
131         out.print("<-- ", inContext(*previousInlineStack[i].inlineCallFrame, context), "\n");
132         hasPrinted = true;
133     }
134     
135     // Print the pushes.
136     for (unsigned i = indexOfDivergence; i < currentInlineStack.size(); ++i) {
137         out.print(prefix);
138         printWhiteSpace(out, i * 2);
139         out.print("--> ", inContext(*currentInlineStack[i].inlineCallFrame, context), "\n");
140         hasPrinted = true;
141     }
142     
143     return hasPrinted;
144 }
145
146 int Graph::amountOfNodeWhiteSpace(Node* node)
147 {
148     return (node->origin.semantic.inlineDepth() - 1) * 2;
149 }
150
151 void Graph::printNodeWhiteSpace(PrintStream& out, Node* node)
152 {
153     printWhiteSpace(out, amountOfNodeWhiteSpace(node));
154 }
155
156 void Graph::dump(PrintStream& out, const char* prefix, Node* node, DumpContext* context)
157 {
158     NodeType op = node->op();
159
160     unsigned refCount = node->refCount();
161     bool mustGenerate = node->mustGenerate();
162     if (mustGenerate)
163         --refCount;
164
165     out.print(prefix);
166     printNodeWhiteSpace(out, node);
167
168     // Example/explanation of dataflow dump output
169     //
170     //   14:   <!2:7>  GetByVal(@3, @13)
171     //   ^1     ^2 ^3     ^4       ^5
172     //
173     // (1) The nodeIndex of this operation.
174     // (2) The reference count. The number printed is the 'real' count,
175     //     not including the 'mustGenerate' ref. If the node is
176     //     'mustGenerate' then the count it prefixed with '!'.
177     // (3) The virtual register slot assigned to this node.
178     // (4) The name of the operation.
179     // (5) The arguments to the operation. The may be of the form:
180     //         @#   - a NodeIndex referencing a prior node in the graph.
181     //         arg# - an argument number.
182     //         id#  - the index in the CodeBlock of an identifier { if codeBlock is passed to dump(), the string representation is displayed }.
183     //         var# - the index of a var on the global object, used by GetGlobalVar/PutGlobalVar operations.
184     out.printf("% 4d:<%c%u:", (int)node->index(), mustGenerate ? '!' : ' ', refCount);
185     if (node->hasResult() && node->hasVirtualRegister() && node->virtualRegister().isValid())
186         out.print(node->virtualRegister());
187     else
188         out.print("-");
189     out.print(">\t", opName(op), "(");
190     CommaPrinter comma;
191     if (node->flags() & NodeHasVarArgs) {
192         for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++) {
193             if (!m_varArgChildren[childIdx])
194                 continue;
195             out.print(comma, m_varArgChildren[childIdx]);
196         }
197     } else {
198         if (!!node->child1() || !!node->child2() || !!node->child3())
199             out.print(comma, node->child1());
200         if (!!node->child2() || !!node->child3())
201             out.print(comma, node->child2());
202         if (!!node->child3())
203             out.print(comma, node->child3());
204     }
205
206     if (toCString(NodeFlagsDump(node->flags())) != "<empty>")
207         out.print(comma, NodeFlagsDump(node->flags()));
208     if (node->prediction())
209         out.print(comma, SpeculationDump(node->prediction()));
210     if (node->hasArrayMode())
211         out.print(comma, node->arrayMode());
212     if (node->hasArithMode())
213         out.print(comma, node->arithMode());
214     if (node->hasVarNumber())
215         out.print(comma, node->varNumber());
216     if (node->hasRegisterPointer())
217         out.print(comma, "global", globalObjectFor(node->origin.semantic)->findRegisterIndex(node->registerPointer()), "(", RawPointer(node->registerPointer()), ")");
218     if (node->hasIdentifier())
219         out.print(comma, "id", node->identifierNumber(), "{", identifiers()[node->identifierNumber()], "}");
220     if (node->hasStructureSet())
221         out.print(comma, inContext(node->structureSet(), context));
222     if (node->hasStructure())
223         out.print(comma, inContext(*node->structure(), context));
224     if (node->hasTransition())
225         out.print(comma, pointerDumpInContext(node->transition(), context));
226     if (node->hasCellOperand()) {
227         if (!node->cellOperand()->value() || !node->cellOperand()->value().isCell())
228             out.print(comma, "invalid cell operand: ", node->cellOperand()->value());
229         else {
230             out.print(comma, pointerDump(node->cellOperand()->value().asCell()));
231             if (node->cellOperand()->value().isCell()) {
232                 CallVariant variant(node->cellOperand()->value().asCell());
233                 if (ExecutableBase* executable = variant.executable()) {
234                     if (executable->isHostFunction())
235                         out.print(comma, "<host function>");
236                     else if (FunctionExecutable* functionExecutable = jsDynamicCast<FunctionExecutable*>(executable))
237                         out.print(comma, FunctionExecutableDump(functionExecutable));
238                     else
239                         out.print(comma, "<non-function executable>");
240                 }
241             }
242         }
243     }
244     if (node->hasFunctionDeclIndex()) {
245         FunctionExecutable* executable = m_codeBlock->functionDecl(node->functionDeclIndex());
246         out.print(comma, FunctionExecutableDump(executable));
247     }
248     if (node->hasFunctionExprIndex()) {
249         FunctionExecutable* executable = m_codeBlock->functionExpr(node->functionExprIndex());
250         out.print(comma, FunctionExecutableDump(executable));
251     }
252     if (node->hasStorageAccessData()) {
253         StorageAccessData& storageAccessData = node->storageAccessData();
254         out.print(comma, "id", storageAccessData.identifierNumber, "{", identifiers()[storageAccessData.identifierNumber], "}");
255         out.print(", ", static_cast<ptrdiff_t>(storageAccessData.offset));
256     }
257     if (node->hasMultiGetByOffsetData()) {
258         MultiGetByOffsetData& data = node->multiGetByOffsetData();
259         out.print(comma, "id", data.identifierNumber, "{", identifiers()[data.identifierNumber], "}");
260         for (unsigned i = 0; i < data.variants.size(); ++i)
261             out.print(comma, inContext(data.variants[i], context));
262     }
263     if (node->hasMultiPutByOffsetData()) {
264         MultiPutByOffsetData& data = node->multiPutByOffsetData();
265         out.print(comma, "id", data.identifierNumber, "{", identifiers()[data.identifierNumber], "}");
266         for (unsigned i = 0; i < data.variants.size(); ++i)
267             out.print(comma, inContext(data.variants[i], context));
268     }
269     ASSERT(node->hasVariableAccessData(*this) == node->hasLocal(*this));
270     if (node->hasVariableAccessData(*this)) {
271         VariableAccessData* variableAccessData = node->tryGetVariableAccessData();
272         if (variableAccessData) {
273             VirtualRegister operand = variableAccessData->local();
274             if (operand.isArgument())
275                 out.print(comma, "arg", operand.toArgument(), "(", VariableAccessDataDump(*this, variableAccessData), ")");
276             else
277                 out.print(comma, "loc", operand.toLocal(), "(", VariableAccessDataDump(*this, variableAccessData), ")");
278             
279             operand = variableAccessData->machineLocal();
280             if (operand.isValid()) {
281                 if (operand.isArgument())
282                     out.print(comma, "machine:arg", operand.toArgument());
283                 else
284                     out.print(comma, "machine:loc", operand.toLocal());
285             }
286         }
287     }
288     if (node->hasUnlinkedLocal()) {
289         VirtualRegister operand = node->unlinkedLocal();
290         if (operand.isArgument())
291             out.print(comma, "arg", operand.toArgument());
292         else
293             out.print(comma, "loc", operand.toLocal());
294     }
295     if (node->hasUnlinkedMachineLocal()) {
296         VirtualRegister operand = node->unlinkedMachineLocal();
297         if (operand.isValid()) {
298             if (operand.isArgument())
299                 out.print(comma, "machine:arg", operand.toArgument());
300             else
301                 out.print(comma, "machine:loc", operand.toLocal());
302         }
303     }
304     if (node->hasConstantBuffer()) {
305         out.print(comma);
306         out.print(node->startConstant(), ":[");
307         CommaPrinter anotherComma;
308         for (unsigned i = 0; i < node->numConstants(); ++i)
309             out.print(anotherComma, pointerDumpInContext(freeze(m_codeBlock->constantBuffer(node->startConstant())[i]), context));
310         out.print("]");
311     }
312     if (node->hasIndexingType())
313         out.print(comma, IndexingTypeDump(node->indexingType()));
314     if (node->hasTypedArrayType())
315         out.print(comma, node->typedArrayType());
316     if (node->hasPhi())
317         out.print(comma, "^", node->phi()->index());
318     if (node->hasExecutionCounter())
319         out.print(comma, RawPointer(node->executionCounter()));
320     if (node->hasVariableWatchpointSet())
321         out.print(comma, RawPointer(node->variableWatchpointSet()));
322     if (node->hasTypedArray())
323         out.print(comma, inContext(JSValue(node->typedArray()), context));
324     if (node->hasStoragePointer())
325         out.print(comma, RawPointer(node->storagePointer()));
326     if (node->isConstant())
327         out.print(comma, pointerDumpInContext(node->constant(), context));
328     if (node->isJump())
329         out.print(comma, "T:", *node->targetBlock());
330     if (node->isBranch())
331         out.print(comma, "T:", node->branchData()->taken, ", F:", node->branchData()->notTaken);
332     if (node->isSwitch()) {
333         SwitchData* data = node->switchData();
334         out.print(comma, data->kind);
335         for (unsigned i = 0; i < data->cases.size(); ++i)
336             out.print(comma, inContext(data->cases[i].value, context), ":", data->cases[i].target);
337         out.print(comma, "default:", data->fallThrough);
338     }
339     ClobberSet reads;
340     ClobberSet writes;
341     addReadsAndWrites(*this, node, reads, writes);
342     if (!reads.isEmpty())
343         out.print(comma, "R:", sortedListDump(reads.direct(), ","));
344     if (!writes.isEmpty())
345         out.print(comma, "W:", sortedListDump(writes.direct(), ","));
346     if (node->origin.isSet()) {
347         out.print(comma, "bc#", node->origin.semantic.bytecodeIndex);
348         if (node->origin.semantic != node->origin.forExit)
349             out.print(comma, "exit: ", node->origin.forExit);
350     }
351     
352     out.print(")");
353
354     if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData())
355         out.print("  predicting ", SpeculationDump(node->tryGetVariableAccessData()->prediction()));
356     else if (node->hasHeapPrediction())
357         out.print("  predicting ", SpeculationDump(node->getHeapPrediction()));
358     
359     out.print("\n");
360 }
361
362 void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
363 {
364     out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "):", block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
365     if (block->executionCount == block->executionCount)
366         out.print(prefix, "  Execution count: ", block->executionCount, "\n");
367     out.print(prefix, "  Predecessors:");
368     for (size_t i = 0; i < block->predecessors.size(); ++i)
369         out.print(" ", *block->predecessors[i]);
370     out.print("\n");
371     if (m_dominators.isValid()) {
372         out.print(prefix, "  Dominated by: ", m_dominators.dominatorsOf(block), "\n");
373         out.print(prefix, "  Dominates: ", m_dominators.blocksDominatedBy(block), "\n");
374         out.print(prefix, "  Dominance Frontier: ", m_dominators.dominanceFrontierOf(block), "\n");
375         out.print(prefix, "  Iterated Dominance Frontier: ", m_dominators.iteratedDominanceFrontierOf(BlockList(1, block)), "\n");
376     }
377     if (m_naturalLoops.isValid()) {
378         if (const NaturalLoop* loop = m_naturalLoops.headerOf(block)) {
379             out.print(prefix, "  Loop header, contains:");
380             Vector<BlockIndex> sortedBlockList;
381             for (unsigned i = 0; i < loop->size(); ++i)
382                 sortedBlockList.append(loop->at(i)->index);
383             std::sort(sortedBlockList.begin(), sortedBlockList.end());
384             for (unsigned i = 0; i < sortedBlockList.size(); ++i)
385                 out.print(" #", sortedBlockList[i]);
386             out.print("\n");
387         }
388         
389         Vector<const NaturalLoop*> containingLoops =
390             m_naturalLoops.loopsOf(block);
391         if (!containingLoops.isEmpty()) {
392             out.print(prefix, "  Containing loop headers:");
393             for (unsigned i = 0; i < containingLoops.size(); ++i)
394                 out.print(" ", *containingLoops[i]->header());
395             out.print("\n");
396         }
397     }
398     if (!block->phis.isEmpty()) {
399         out.print(prefix, "  Phi Nodes:");
400         for (size_t i = 0; i < block->phis.size(); ++i) {
401             Node* phiNode = block->phis[i];
402             if (!phiNode->shouldGenerate() && phiNodeDumpMode == DumpLivePhisOnly)
403                 continue;
404             out.print(" @", phiNode->index(), "<", phiNode->refCount(), ">->(");
405             if (phiNode->child1()) {
406                 out.print("@", phiNode->child1()->index());
407                 if (phiNode->child2()) {
408                     out.print(", @", phiNode->child2()->index());
409                     if (phiNode->child3())
410                         out.print(", @", phiNode->child3()->index());
411                 }
412             }
413             out.print(")", i + 1 < block->phis.size() ? "," : "");
414         }
415         out.print("\n");
416     }
417 }
418
419 void Graph::dump(PrintStream& out, DumpContext* context)
420 {
421     DumpContext myContext;
422     myContext.graph = this;
423     if (!context)
424         context = &myContext;
425     
426     out.print("\n");
427     out.print("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n");
428     out.print("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
429     out.print("\n");
430     
431     Node* lastNode = 0;
432     for (size_t b = 0; b < m_blocks.size(); ++b) {
433         BasicBlock* block = m_blocks[b].get();
434         if (!block)
435             continue;
436         dumpBlockHeader(out, "", block, DumpAllPhis, context);
437         out.print("  States: ", block->cfaStructureClobberStateAtHead);
438         if (!block->cfaHasVisited)
439             out.print(", CurrentlyCFAUnreachable");
440         if (!block->intersectionOfCFAHasVisited)
441             out.print(", CFAUnreachable");
442         out.print("\n");
443         switch (m_form) {
444         case LoadStore:
445         case ThreadedCPS: {
446             out.print("  Vars Before: ");
447             if (block->cfaHasVisited)
448                 out.print(inContext(block->valuesAtHead, context));
449             else
450                 out.print("<empty>");
451             out.print("\n");
452             out.print("  Intersected Vars Before: ");
453             if (block->intersectionOfCFAHasVisited)
454                 out.print(inContext(block->intersectionOfPastValuesAtHead, context));
455             else
456                 out.print("<empty>");
457             out.print("\n");
458             out.print("  Var Links: ", block->variablesAtHead, "\n");
459             break;
460         }
461             
462         case SSA: {
463             RELEASE_ASSERT(block->ssa);
464             out.print("  Availability: ", block->ssa->availabilityAtHead, "\n");
465             out.print("  Live: ", nodeListDump(block->ssa->liveAtHead), "\n");
466             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtHead, context), "\n");
467             break;
468         } }
469         for (size_t i = 0; i < block->size(); ++i) {
470             dumpCodeOrigin(out, "", lastNode, block->at(i), context);
471             dump(out, "", block->at(i), context);
472             lastNode = block->at(i);
473         }
474         out.print("  States: ", block->cfaBranchDirection, ", ", block->cfaStructureClobberStateAtTail);
475         if (!block->cfaDidFinish)
476             out.print(", CFAInvalidated");
477         out.print("\n");
478         switch (m_form) {
479         case LoadStore:
480         case ThreadedCPS: {
481             out.print("  Vars After: ");
482             if (block->cfaHasVisited)
483                 out.print(inContext(block->valuesAtTail, context));
484             else
485                 out.print("<empty>");
486             out.print("\n");
487             out.print("  Var Links: ", block->variablesAtTail, "\n");
488             break;
489         }
490             
491         case SSA: {
492             RELEASE_ASSERT(block->ssa);
493             out.print("  Availability: ", block->ssa->availabilityAtTail, "\n");
494             out.print("  Live: ", nodeListDump(block->ssa->liveAtTail), "\n");
495             out.print("  Values: ", nodeMapDump(block->ssa->valuesAtTail, context), "\n");
496             break;
497         } }
498         out.print("\n");
499     }
500     
501     if (!myContext.isEmpty()) {
502         myContext.dump(out);
503         out.print("\n");
504     }
505 }
506
507 void Graph::dethread()
508 {
509     if (m_form == LoadStore || m_form == SSA)
510         return;
511     
512     if (logCompilationChanges())
513         dataLog("Dethreading DFG graph.\n");
514     
515     SamplingRegion samplingRegion("DFG Dethreading");
516     
517     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
518         BasicBlock* block = m_blocks[blockIndex].get();
519         if (!block)
520             continue;
521         for (unsigned phiIndex = block->phis.size(); phiIndex--;) {
522             Node* phi = block->phis[phiIndex];
523             phi->children.reset();
524         }
525     }
526     
527     m_form = LoadStore;
528 }
529
530 void Graph::handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock* block, BasicBlock* successor)
531 {
532     if (!successor->isReachable) {
533         successor->isReachable = true;
534         worklist.append(successor);
535     }
536     
537     successor->predecessors.append(block);
538 }
539
540 void Graph::determineReachability()
541 {
542     Vector<BasicBlock*, 16> worklist;
543     worklist.append(block(0));
544     block(0)->isReachable = true;
545     while (!worklist.isEmpty()) {
546         BasicBlock* block = worklist.takeLast();
547         for (unsigned i = block->numSuccessors(); i--;)
548             handleSuccessor(worklist, block, block->successor(i));
549     }
550 }
551
552 void Graph::resetReachability()
553 {
554     for (BlockIndex blockIndex = m_blocks.size(); blockIndex--;) {
555         BasicBlock* block = m_blocks[blockIndex].get();
556         if (!block)
557             continue;
558         block->isReachable = false;
559         block->predecessors.clear();
560     }
561     
562     determineReachability();
563 }
564
565 namespace {
566
567 class RefCountCalculator {
568 public:
569     RefCountCalculator(Graph& graph)
570         : m_graph(graph)
571     {
572     }
573     
574     void calculate()
575     {
576         // First reset the counts to 0 for all nodes.
577         //
578         // Also take this opportunity to pretend that Check nodes are not NodeMustGenerate. Check
579         // nodes are MustGenerate because they are executed for effect, but they follow the same
580         // DCE rules as nodes that aren't MustGenerate: they only contribute to the ref count of
581         // their children if the edges require checks. Non-checking edges are removed. Note that
582         // for any Checks left over, this phase will turn them back into NodeMustGenerate.
583         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
584             BasicBlock* block = m_graph.block(blockIndex);
585             if (!block)
586                 continue;
587             for (unsigned indexInBlock = block->size(); indexInBlock--;)
588                 block->at(indexInBlock)->setRefCount(0);
589             for (unsigned phiIndex = block->phis.size(); phiIndex--;)
590                 block->phis[phiIndex]->setRefCount(0);
591         }
592     
593         // Now find the roots:
594         // - Nodes that are must-generate.
595         // - Nodes that are reachable from type checks.
596         // Set their ref counts to 1 and put them on the worklist.
597         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
598             BasicBlock* block = m_graph.block(blockIndex);
599             if (!block)
600                 continue;
601             for (unsigned indexInBlock = block->size(); indexInBlock--;) {
602                 Node* node = block->at(indexInBlock);
603                 DFG_NODE_DO_TO_CHILDREN(m_graph, node, findTypeCheckRoot);
604                 if (!(node->flags() & NodeMustGenerate))
605                     continue;
606                 if (node->op() == Check) {
607                     // We don't treat Check nodes as MustGenerate. We will gladly
608                     // kill them off in this phase.
609                     continue;
610                 }
611                 if (!node->postfixRef())
612                     m_worklist.append(node);
613             }
614         }
615         
616         while (!m_worklist.isEmpty()) {
617             while (!m_worklist.isEmpty()) {
618                 Node* node = m_worklist.last();
619                 m_worklist.removeLast();
620                 ASSERT(node->shouldGenerate()); // It should not be on the worklist unless it's ref'ed.
621                 DFG_NODE_DO_TO_CHILDREN(m_graph, node, countEdge);
622             }
623             
624             if (m_graph.m_form == SSA) {
625                 // Find Phi->Upsilon edges, which are represented as meta-data in the
626                 // Upsilon.
627                 for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
628                     BasicBlock* block = m_graph.block(blockIndex);
629                     if (!block)
630                         continue;
631                     for (unsigned nodeIndex = block->size(); nodeIndex--;) {
632                         Node* node = block->at(nodeIndex);
633                         if (node->op() != Upsilon)
634                             continue;
635                         if (node->shouldGenerate())
636                             continue;
637                         if (node->phi()->shouldGenerate())
638                             countNode(node);
639                     }
640                 }
641             }
642         }
643     }
644     
645 private:
646     void findTypeCheckRoot(Node*, Edge edge)
647     {
648         // We may have an "unproved" untyped use for code that is unreachable. The CFA
649         // will just not have gotten around to it.
650         if (edge.isProved() || edge.willNotHaveCheck())
651             return;
652         if (!edge->postfixRef())
653             m_worklist.append(edge.node());
654     }
655     
656     void countNode(Node* node)
657     {
658         if (node->postfixRef())
659             return;
660         m_worklist.append(node);
661     }
662     
663     void countEdge(Node*, Edge edge)
664     {
665         // Don't count edges that are already counted for their type checks.
666         if (!(edge.isProved() || edge.willNotHaveCheck()))
667             return;
668         countNode(edge.node());
669     }
670     
671     Graph& m_graph;
672     Vector<Node*, 128> m_worklist;
673 };
674
675 } // anonymous namespace
676
677 void Graph::computeRefCounts()
678 {
679     RefCountCalculator calculator(*this);
680     calculator.calculate();
681 }
682
683 void Graph::killBlockAndItsContents(BasicBlock* block)
684 {
685     for (unsigned phiIndex = block->phis.size(); phiIndex--;)
686         m_allocator.free(block->phis[phiIndex]);
687     for (unsigned nodeIndex = block->size(); nodeIndex--;)
688         m_allocator.free(block->at(nodeIndex));
689     
690     killBlock(block);
691 }
692
693 void Graph::killUnreachableBlocks()
694 {
695     for (BlockIndex blockIndex = 0; blockIndex < numBlocks(); ++blockIndex) {
696         BasicBlock* block = this->block(blockIndex);
697         if (!block)
698             continue;
699         if (block->isReachable)
700             continue;
701         
702         killBlockAndItsContents(block);
703     }
704 }
705
706 void Graph::invalidateCFG()
707 {
708     m_dominators.invalidate();
709     m_naturalLoops.invalidate();
710 }
711
712 void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal)
713 {
714     if (variableAccessData->isCaptured()) {
715         // Let CSE worry about this one.
716         return;
717     }
718     for (unsigned indexInBlock = startIndexInBlock; indexInBlock < block.size(); ++indexInBlock) {
719         Node* node = block[indexInBlock];
720         bool shouldContinue = true;
721         switch (node->op()) {
722         case SetLocal: {
723             if (node->local() == variableAccessData->local())
724                 shouldContinue = false;
725             break;
726         }
727                 
728         case GetLocal: {
729             if (node->variableAccessData() != variableAccessData)
730                 continue;
731             substitute(block, indexInBlock, node, newGetLocal);
732             Node* oldTailNode = block.variablesAtTail.operand(variableAccessData->local());
733             if (oldTailNode == node)
734                 block.variablesAtTail.operand(variableAccessData->local()) = newGetLocal;
735             shouldContinue = false;
736             break;
737         }
738                 
739         default:
740             break;
741         }
742         if (!shouldContinue)
743             break;
744     }
745 }
746
747 BlockList Graph::blocksInPreOrder()
748 {
749     BlockList result;
750     BlockWorklist worklist;
751     worklist.push(block(0));
752     while (BasicBlock* block = worklist.pop()) {
753         result.append(block);
754         for (unsigned i = block->numSuccessors(); i--;)
755             worklist.push(block->successor(i));
756     }
757     return result;
758 }
759
760 BlockList Graph::blocksInPostOrder()
761 {
762     BlockList result;
763     PostOrderBlockWorklist worklist;
764     worklist.push(block(0));
765     while (BlockWithOrder item = worklist.pop()) {
766         switch (item.order) {
767         case PreOrder:
768             worklist.pushPost(item.block);
769             for (unsigned i = item.block->numSuccessors(); i--;)
770                 worklist.push(item.block->successor(i));
771             break;
772         case PostOrder:
773             result.append(item.block);
774             break;
775         }
776     }
777     return result;
778 }
779
780 void Graph::clearReplacements()
781 {
782     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
783         BasicBlock* block = m_blocks[blockIndex].get();
784         if (!block)
785             continue;
786         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
787             block->phis[phiIndex]->replacement = 0;
788         for (unsigned nodeIndex = block->size(); nodeIndex--;)
789             block->at(nodeIndex)->replacement = 0;
790     }
791 }
792
793 void Graph::initializeNodeOwners()
794 {
795     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
796         BasicBlock* block = m_blocks[blockIndex].get();
797         if (!block)
798             continue;
799         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
800             block->phis[phiIndex]->owner = block;
801         for (unsigned nodeIndex = block->size(); nodeIndex--;)
802             block->at(nodeIndex)->owner = block;
803     }
804 }
805
806 void Graph::clearFlagsOnAllNodes(NodeFlags flags)
807 {
808     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
809         BasicBlock* block = m_blocks[blockIndex].get();
810         if (!block)
811             continue;
812         for (unsigned phiIndex = block->phis.size(); phiIndex--;)
813             block->phis[phiIndex]->clearFlags(flags);
814         for (unsigned nodeIndex = block->size(); nodeIndex--;)
815             block->at(nodeIndex)->clearFlags(flags);
816     }
817 }
818
819 FullBytecodeLiveness& Graph::livenessFor(CodeBlock* codeBlock)
820 {
821     HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>>::iterator iter = m_bytecodeLiveness.find(codeBlock);
822     if (iter != m_bytecodeLiveness.end())
823         return *iter->value;
824     
825     std::unique_ptr<FullBytecodeLiveness> liveness = std::make_unique<FullBytecodeLiveness>();
826     codeBlock->livenessAnalysis().computeFullLiveness(*liveness);
827     FullBytecodeLiveness& result = *liveness;
828     m_bytecodeLiveness.add(codeBlock, WTF::move(liveness));
829     return result;
830 }
831
832 FullBytecodeLiveness& Graph::livenessFor(InlineCallFrame* inlineCallFrame)
833 {
834     return livenessFor(baselineCodeBlockFor(inlineCallFrame));
835 }
836
837 bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin)
838 {
839     for (;;) {
840         VirtualRegister reg = VirtualRegister(
841             operand.offset() - codeOrigin.stackOffset());
842         
843         if (operand.offset() < codeOrigin.stackOffset() + JSStack::CallFrameHeaderSize) {
844             if (reg.isArgument()) {
845                 RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize);
846                 
847                 if (!codeOrigin.inlineCallFrame->isClosureCall)
848                     return false;
849                 
850                 if (reg.offset() == JSStack::Callee)
851                     return true;
852                 if (reg.offset() == JSStack::ScopeChain)
853                     return true;
854                 
855                 return false;
856             }
857             
858             return livenessFor(codeOrigin.inlineCallFrame).operandIsLive(
859                 reg.offset(), codeOrigin.bytecodeIndex);
860         }
861         
862         InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
863         if (!inlineCallFrame)
864             break;
865
866         // Arguments are always live. This would be redundant if it wasn't for our
867         // op_call_varargs inlining.
868         // FIXME: 'this' might not be live, but we don't have a way of knowing.
869         // https://bugs.webkit.org/show_bug.cgi?id=128519
870         if (reg.isArgument()
871             && static_cast<size_t>(reg.toArgument()) < inlineCallFrame->arguments.size())
872             return true;
873         
874         codeOrigin = inlineCallFrame->caller;
875     }
876     
877     return true;
878 }
879
880 unsigned Graph::frameRegisterCount()
881 {
882     unsigned result = m_nextMachineLocal + std::max(m_parameterSlots, static_cast<unsigned>(maxFrameExtentForSlowPathCallInRegisters));
883     return roundLocalRegisterCountForFramePointerOffset(result);
884 }
885
886 unsigned Graph::stackPointerOffset()
887 {
888     return virtualRegisterForLocal(frameRegisterCount() - 1).offset();
889 }
890
891 unsigned Graph::requiredRegisterCountForExit()
892 {
893     unsigned count = JIT::frameRegisterCountFor(m_profiledBlock);
894     for (InlineCallFrameSet::iterator iter = m_plan.inlineCallFrames->begin(); !!iter; ++iter) {
895         InlineCallFrame* inlineCallFrame = *iter;
896         CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
897         unsigned requiredCount = VirtualRegister(inlineCallFrame->stackOffset).toLocal() + 1 + JIT::frameRegisterCountFor(codeBlock);
898         count = std::max(count, requiredCount);
899     }
900     return count;
901 }
902
903 unsigned Graph::requiredRegisterCountForExecutionAndExit()
904 {
905     return std::max(frameRegisterCount(), requiredRegisterCountForExit());
906 }
907
908 JSValue Graph::tryGetConstantProperty(
909     JSValue base, const StructureSet& structureSet, PropertyOffset offset)
910 {
911     if (!base || !base.isObject())
912         return JSValue();
913     
914     JSObject* object = asObject(base);
915     
916     for (unsigned i = structureSet.size(); i--;) {
917         Structure* structure = structureSet[i];
918         WatchpointSet* set = structure->propertyReplacementWatchpointSet(offset);
919         if (!set || !set->isStillValid())
920             return JSValue();
921         
922         ASSERT(structure->isValidOffset(offset));
923         ASSERT(!structure->isUncacheableDictionary());
924         
925         watchpoints().addLazily(set);
926     }
927     
928     // What follows may require some extra thought. We need this load to load a valid JSValue. If
929     // our profiling makes sense and we're still on track to generate code that won't be
930     // invalidated, then we have nothing to worry about. We do, however, have to worry about
931     // loading - and then using - an invalid JSValue in the case that unbeknownst to us our code
932     // is doomed.
933     //
934     // One argument in favor of this code is that it should definitely work because the butterfly
935     // is always set before the structure. However, we don't currently have a fence between those
936     // stores. It's not clear if this matters, however. We don't ever shrink the property storage.
937     // So, for this to fail, you'd need an access on a constant object pointer such that the inline
938     // caches told us that the object had a structure that it did not *yet* have, and then later,
939     // the object transitioned to that structure that the inline caches had alraedy seen. And then
940     // the processor reordered the stores. Seems unlikely and difficult to test. I believe that
941     // this is worth revisiting but it isn't worth losing sleep over. Filed:
942     // https://bugs.webkit.org/show_bug.cgi?id=134641
943     //
944     // For now, we just do the minimal thing: defend against the structure right now being
945     // incompatible with the getDirect we're trying to do. The easiest way to do that is to
946     // determine if the structure belongs to the proven set.
947     
948     if (!structureSet.contains(object->structure()))
949         return JSValue();
950     
951     return object->getDirect(offset);
952 }
953
954 JSValue Graph::tryGetConstantProperty(JSValue base, Structure* structure, PropertyOffset offset)
955 {
956     return tryGetConstantProperty(base, StructureSet(structure), offset);
957 }
958
959 JSValue Graph::tryGetConstantProperty(
960     JSValue base, const StructureAbstractValue& structure, PropertyOffset offset)
961 {
962     if (structure.isTop() || structure.isClobbered())
963         return JSValue();
964     
965     return tryGetConstantProperty(base, structure.set(), offset);
966 }
967
968 JSValue Graph::tryGetConstantProperty(const AbstractValue& base, PropertyOffset offset)
969 {
970     return tryGetConstantProperty(base.m_value, base.m_structure, offset);
971 }
972
973 JSLexicalEnvironment* Graph::tryGetActivation(Node* node)
974 {
975     return node->dynamicCastConstant<JSLexicalEnvironment*>();
976 }
977
978 WriteBarrierBase<Unknown>* Graph::tryGetRegisters(Node* node)
979 {
980     JSLexicalEnvironment* lexicalEnvironment = tryGetActivation(node);
981     if (!lexicalEnvironment)
982         return 0;
983     if (!lexicalEnvironment->isTornOff())
984         return 0;
985     return lexicalEnvironment->registers();
986 }
987
988 JSArrayBufferView* Graph::tryGetFoldableView(Node* node)
989 {
990     JSArrayBufferView* view = node->dynamicCastConstant<JSArrayBufferView*>();
991     if (!view)
992         return nullptr;
993     if (!view->length())
994         return nullptr;
995     WTF::loadLoadFence();
996     return view;
997 }
998
999 JSArrayBufferView* Graph::tryGetFoldableView(Node* node, ArrayMode arrayMode)
1000 {
1001     if (arrayMode.typedArrayType() == NotTypedArray)
1002         return 0;
1003     return tryGetFoldableView(node);
1004 }
1005
1006 JSArrayBufferView* Graph::tryGetFoldableViewForChild1(Node* node)
1007 {
1008     return tryGetFoldableView(child(node, 0).node(), node->arrayMode());
1009 }
1010
1011 void Graph::registerFrozenValues()
1012 {
1013     m_codeBlock->constants().resize(0);
1014     for (FrozenValue* value : m_frozenValues) {
1015         if (value->structure())
1016             ASSERT(m_plan.weakReferences.contains(value->structure()));
1017         
1018         switch (value->strength()) {
1019         case FragileValue: {
1020             break;
1021         }
1022         case WeakValue: {
1023             m_plan.weakReferences.addLazily(value->value().asCell());
1024             break;
1025         }
1026         case StrongValue: {
1027             unsigned constantIndex = m_codeBlock->addConstantLazily();
1028             initializeLazyWriteBarrierForConstant(
1029                 m_plan.writeBarriers,
1030                 m_codeBlock->constants()[constantIndex],
1031                 m_codeBlock,
1032                 constantIndex,
1033                 m_codeBlock->ownerExecutable(),
1034                 value->value());
1035             break;
1036         } }
1037     }
1038     m_codeBlock->constants().shrinkToFit();
1039 }
1040
1041 void Graph::visitChildren(SlotVisitor& visitor)
1042 {
1043     for (FrozenValue* value : m_frozenValues) {
1044         visitor.appendUnbarrieredReadOnlyValue(value->value());
1045         visitor.appendUnbarrieredReadOnlyPointer(value->structure());
1046     }
1047     
1048     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
1049         BasicBlock* block = this->block(blockIndex);
1050         if (!block)
1051             continue;
1052         
1053         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
1054             Node* node = block->at(nodeIndex);
1055             
1056             switch (node->op()) {
1057             case CheckStructure:
1058                 for (unsigned i = node->structureSet().size(); i--;)
1059                     visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]);
1060                 break;
1061                 
1062             case NewObject:
1063             case ArrayifyToStructure:
1064             case NewStringObject:
1065                 visitor.appendUnbarrieredReadOnlyPointer(node->structure());
1066                 break;
1067                 
1068             case PutStructure:
1069             case AllocatePropertyStorage:
1070             case ReallocatePropertyStorage:
1071                 visitor.appendUnbarrieredReadOnlyPointer(
1072                     node->transition()->previous);
1073                 visitor.appendUnbarrieredReadOnlyPointer(
1074                     node->transition()->next);
1075                 break;
1076                 
1077             case MultiGetByOffset:
1078                 for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) {
1079                     GetByIdVariant& variant = node->multiGetByOffsetData().variants[i];
1080                     const StructureSet& set = variant.structureSet();
1081                     for (unsigned j = set.size(); j--;)
1082                         visitor.appendUnbarrieredReadOnlyPointer(set[j]);
1083
1084                     // Don't need to mark anything in the structure chain because that would
1085                     // have been decomposed into CheckStructure's. Don't need to mark the
1086                     // callLinkStatus because we wouldn't use MultiGetByOffset if any of the
1087                     // variants did that.
1088                     ASSERT(!variant.callLinkStatus());
1089                 }
1090                 break;
1091                     
1092             case MultiPutByOffset:
1093                 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
1094                     PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
1095                     const StructureSet& set = variant.oldStructure();
1096                     for (unsigned j = set.size(); j--;)
1097                         visitor.appendUnbarrieredReadOnlyPointer(set[j]);
1098                     if (variant.kind() == PutByIdVariant::Transition)
1099                         visitor.appendUnbarrieredReadOnlyPointer(variant.newStructure());
1100                 }
1101                 break;
1102                 
1103             default:
1104                 break;
1105             }
1106         }
1107     }
1108 }
1109
1110 FrozenValue* Graph::freezeFragile(JSValue value)
1111 {
1112     if (UNLIKELY(!value))
1113         return FrozenValue::emptySingleton();
1114     
1115     auto result = m_frozenValueMap.add(JSValue::encode(value), nullptr);
1116     if (LIKELY(!result.isNewEntry))
1117         return result.iterator->value;
1118     
1119     return result.iterator->value = m_frozenValues.add(FrozenValue::freeze(value));
1120 }
1121
1122 FrozenValue* Graph::freeze(JSValue value)
1123 {
1124     FrozenValue* result = freezeFragile(value);
1125     result->strengthenTo(WeakValue);
1126     return result;
1127 }
1128
1129 FrozenValue* Graph::freezeStrong(JSValue value)
1130 {
1131     FrozenValue* result = freezeFragile(value);
1132     result->strengthenTo(StrongValue);
1133     return result;
1134 }
1135
1136 void Graph::convertToConstant(Node* node, FrozenValue* value)
1137 {
1138     if (value->structure())
1139         assertIsRegistered(value->structure());
1140     if (m_form == ThreadedCPS) {
1141         if (node->op() == GetLocal)
1142             dethread();
1143         else
1144             ASSERT(!node->hasVariableAccessData(*this));
1145     }
1146     node->convertToConstant(value);
1147 }
1148
1149 void Graph::convertToConstant(Node* node, JSValue value)
1150 {
1151     convertToConstant(node, freeze(value));
1152 }
1153
1154 void Graph::convertToStrongConstant(Node* node, JSValue value)
1155 {
1156     convertToConstant(node, freezeStrong(value));
1157 }
1158
1159 StructureRegistrationResult Graph::registerStructure(Structure* structure)
1160 {
1161     m_plan.weakReferences.addLazily(structure);
1162     if (m_plan.watchpoints.consider(structure))
1163         return StructureRegisteredAndWatched;
1164     return StructureRegisteredNormally;
1165 }
1166
1167 void Graph::assertIsRegistered(Structure* structure)
1168 {
1169     if (m_structureRegistrationState == HaveNotStartedRegistering)
1170         return;
1171     
1172     DFG_ASSERT(*this, nullptr, m_plan.weakReferences.contains(structure));
1173     
1174     if (!structure->dfgShouldWatch())
1175         return;
1176     if (watchpoints().isWatched(structure->transitionWatchpointSet()))
1177         return;
1178     
1179     DFG_CRASH(*this, nullptr, toCString("Structure ", pointerDump(structure), " is watchable but isn't being watched.").data());
1180 }
1181
1182 void Graph::handleAssertionFailure(
1183     Node* node, const char* file, int line, const char* function, const char* assertion)
1184 {
1185     startCrashing();
1186     dataLog("DFG ASSERTION FAILED: ", assertion, "\n");
1187     dataLog(file, "(", line, ") : ", function, "\n");
1188     dataLog("\n");
1189     if (node) {
1190         dataLog("While handling node ", node, "\n");
1191         dataLog("\n");
1192     }
1193     dataLog("Graph at time of failure:\n");
1194     dump();
1195     dataLog("\n");
1196     dataLog("DFG ASSERTION FAILED: ", assertion, "\n");
1197     dataLog(file, "(", line, ") : ", function, "\n");
1198     CRASH();
1199 }
1200
1201 } } // namespace JSC::DFG
1202
1203 #endif // ENABLE(DFG_JIT)