6578a963d135cb140714f4c7e10683dcbfac5c51
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGValidate.cpp
1 /*
2  * Copyright (C) 2012-2015 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 "DFGValidate.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "CodeBlockWithJITType.h"
32 #include "DFGMayExit.h"
33 #include "JSCInlines.h"
34 #include <wtf/Assertions.h>
35 #include <wtf/BitVector.h>
36
37 namespace JSC { namespace DFG {
38
39 class Validate {
40 public:
41     Validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase)
42         : m_graph(graph)
43         , m_graphDumpMode(graphDumpMode)
44         , m_graphDumpBeforePhase(graphDumpBeforePhase)
45     {
46     }
47     
48     #define VALIDATE(context, assertion) do { \
49         if (!(assertion)) { \
50             startCrashing(); \
51             dataLogF("\n\n\nAt "); \
52             reportValidationContext context; \
53             dataLogF(": validation failed: %s (%s:%d).\n", #assertion, __FILE__, __LINE__); \
54             dumpGraphIfAppropriate(); \
55             WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
56             CRASH(); \
57         } \
58     } while (0)
59     
60     #define V_EQUAL(context, left, right) do { \
61         if (left != right) { \
62             startCrashing(); \
63             dataLogF("\n\n\nAt "); \
64             reportValidationContext context; \
65             dataLogF(": validation failed: (%s = ", #left); \
66             dataLog(left); \
67             dataLogF(") == (%s = ", #right); \
68             dataLog(right); \
69             dataLogF(") (%s:%d).\n", __FILE__, __LINE__); \
70             dumpGraphIfAppropriate(); \
71             WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \
72             CRASH(); \
73         } \
74     } while (0)
75
76     #define notSet (static_cast<size_t>(-1))
77         
78     void validate()
79     {
80         // NB. This code is not written for performance, since it is not intended to run
81         // in release builds.
82
83         // Validate that all local variables at the head of the root block are dead.
84         BasicBlock* root = m_graph.block(0);
85         for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i)
86             V_EQUAL((virtualRegisterForLocal(i), root), static_cast<Node*>(0), root->variablesAtHead.local(i));
87         
88         // Validate ref counts and uses.
89         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
90             BasicBlock* block = m_graph.block(blockIndex);
91             if (!block)
92                 continue;
93             VALIDATE((block), block->isReachable);
94             for (size_t i = 0; i < block->numNodes(); ++i)
95                 m_myRefCounts.add(block->node(i), 0);
96         }
97         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
98             BasicBlock* block = m_graph.block(blockIndex);
99             if (!block)
100                 continue;
101             for (size_t i = 0; i < block->numNodes(); ++i) {
102                 Node* node = block->node(i);
103                 m_acceptableNodes.add(node);
104                 if (!node->shouldGenerate())
105                     continue;
106                 if (node->op() == Upsilon) {
107                     VALIDATE((node), m_graph.m_form == SSA);
108                     if (node->phi()->shouldGenerate())
109                         m_myRefCounts.find(node)->value++;
110                 }
111                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
112                     // Phi children in LoadStore form are invalid.
113                     if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
114                         continue;
115                     
116                     Edge edge = m_graph.child(node, j);
117                     if (!edge)
118                         continue;
119                     
120                     m_myRefCounts.find(edge.node())->value++;
121
122                     validateEdgeWithDoubleResultIfNecessary(node, edge);
123                     VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse));
124                     
125                     if (m_graph.m_form == SSA) {
126                         // In SSA, all edges must hasResult().
127                         VALIDATE((node, edge), edge->hasResult());
128                         continue;
129                     }
130                     
131                     // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult().
132                     switch (node->op()) {
133                     case Flush:
134                     case GetLocal:
135                         VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
136                         VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
137                         break;
138                     case PhantomLocal:
139                         VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
140                         VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
141                         VALIDATE((node, edge), edge->op() != SetLocal);
142                         break;
143                     case Phi:
144                         VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
145                         if (m_graph.m_unificationState == LocallyUnified)
146                             break;
147                         VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
148                         break;
149                     default:
150                         VALIDATE((node, edge), edge->hasResult());
151                         break;
152                     }
153                 }
154             }
155         }
156         
157         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
158             BasicBlock* block = m_graph.block(blockIndex);
159             if (!block)
160                 continue;
161             for (size_t i = 0; i < block->numNodes(); ++i) {
162                 Node* node = block->node(i);
163                 if (m_graph.m_refCountState == ExactRefCount)
164                     V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount());
165             }
166             
167             bool foundTerminal = false;
168             for (size_t i = 0 ; i < block->size(); ++i) {
169                 Node* node = block->at(i);
170                 if (node->isTerminal()) {
171                     foundTerminal = true;
172                     for (size_t j = i + 1; j < block->size(); ++j) {
173                         node = block->at(j);
174                         VALIDATE((node), node->op() == Phantom || node->op() == PhantomLocal || node->op() == Flush || node->op() == Check);
175                         m_graph.doToChildren(
176                             node,
177                             [&] (Edge edge) {
178                                 VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind()));
179                             });
180                     }
181                     break;
182                 }
183             }
184             VALIDATE((block), foundTerminal);
185             
186             for (size_t i = 0; i < block->size(); ++i) {
187                 Node* node = block->at(i);
188                 
189                 VALIDATE((node), node->origin.semantic.isSet() == node->origin.forExit.isSet());
190                 VALIDATE((node), !mayExit(m_graph, node) || node->origin.forExit.isSet());
191                 VALIDATE((node), !node->hasStructure() || !!node->structure());
192                 VALIDATE((node), !node->hasCellOperand() || node->cellOperand()->value().isCell());
193                 VALIDATE((node), !node->hasCellOperand() || !!node->cellOperand()->value());
194                  
195                 if (!(node->flags() & NodeHasVarArgs)) {
196                     if (!node->child2())
197                         VALIDATE((node), !node->child3());
198                     if (!node->child1())
199                         VALIDATE((node), !node->child2());
200                 }
201                  
202                 switch (node->op()) {
203                 case Identity:
204                     VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result()));
205                     break;
206                 case SetLocal:
207                 case PutStack:
208                 case Upsilon:
209                     VALIDATE((node), !!node->child1());
210                     switch (node->child1().useKind()) {
211                     case UntypedUse:
212                     case CellUse:
213                     case Int32Use:
214                     case Int52RepUse:
215                     case DoubleRepUse:
216                     case BooleanUse:
217                         break;
218                     default:
219                         VALIDATE((node), !"Bad use kind");
220                         break;
221                     }
222                     break;
223                 case MakeRope:
224                 case ValueAdd:
225                 case ArithAdd:
226                 case ArithSub:
227                 case ArithMul:
228                 case ArithIMul:
229                 case ArithDiv:
230                 case ArithMod:
231                 case ArithMin:
232                 case ArithMax:
233                 case ArithPow:
234                 case CompareLess:
235                 case CompareLessEq:
236                 case CompareGreater:
237                 case CompareGreaterEq:
238                 case CompareEq:
239                 case CompareEqConstant:
240                 case CompareStrictEq:
241                     VALIDATE((node), !!node->child1());
242                     VALIDATE((node), !!node->child2());
243                     break;
244                 case PutStructure:
245                     VALIDATE((node), !node->transition()->previous->dfgShouldWatch());
246                     break;
247                 case MultiPutByOffset:
248                     for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
249                         const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
250                         if (variant.kind() != PutByIdVariant::Transition)
251                             continue;
252                         VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch());
253                     }
254                     break;
255                 case DoubleConstant:
256                 case Int52Constant:
257                     VALIDATE((node), node->isNumberConstant());
258                     break;
259                 default:
260                     break;
261                 }
262             }
263         }
264         
265         switch (m_graph.m_form) {
266         case LoadStore:
267         case ThreadedCPS:
268             validateCPS();
269             break;
270             
271         case SSA:
272             validateSSA();
273             break;
274         }
275     }
276     
277 private:
278     Graph& m_graph;
279     GraphDumpMode m_graphDumpMode;
280     CString m_graphDumpBeforePhase;
281     
282     HashMap<Node*, unsigned> m_myRefCounts;
283     HashSet<Node*> m_acceptableNodes;
284     
285     void validateCPS()
286     {
287         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
288             BasicBlock* block = m_graph.block(blockIndex);
289             if (!block)
290                 continue;
291             
292             HashSet<Node*> phisInThisBlock;
293             HashSet<Node*> nodesInThisBlock;
294             
295             for (size_t i = 0; i < block->numNodes(); ++i) {
296                 Node* node = block->node(i);
297                 nodesInThisBlock.add(node);
298                 if (block->isPhiIndex(i))
299                     phisInThisBlock.add(node);
300                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
301                     Edge edge = m_graph.child(node, j);
302                     if (!edge)
303                         continue;
304                     VALIDATE((node, edge), m_acceptableNodes.contains(edge.node()));
305                 }
306             }
307             
308             for (size_t i = 0; i < block->phis.size(); ++i) {
309                 Node* node = block->phis[i];
310                 ASSERT(phisInThisBlock.contains(node));
311                 VALIDATE((node), node->op() == Phi);
312                 VirtualRegister local = node->local();
313                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
314                     // Phi children in LoadStore form are invalid.
315                     if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
316                         continue;
317                     
318                     Edge edge = m_graph.child(node, j);
319                     if (!edge)
320                         continue;
321                     
322                     VALIDATE(
323                         (node, edge),
324                         edge->op() == SetLocal
325                         || edge->op() == SetArgument
326                         || edge->op() == Flush
327                         || edge->op() == Phi);
328                     
329                     if (phisInThisBlock.contains(edge.node()))
330                         continue;
331                     
332                     if (nodesInThisBlock.contains(edge.node())) {
333                         VALIDATE(
334                             (node, edge),
335                             edge->op() == SetLocal
336                             || edge->op() == SetArgument
337                             || edge->op() == Flush);
338                         
339                         continue;
340                     }
341                     
342                     // There must exist a predecessor block that has this node index in
343                     // its tail variables.
344                     bool found = false;
345                     for (unsigned k = 0; k < block->predecessors.size(); ++k) {
346                         BasicBlock* prevBlock = block->predecessors[k];
347                         VALIDATE((block->predecessors[k]), prevBlock);
348                         Node* prevNode = prevBlock->variablesAtTail.operand(local);
349                         // If we have a Phi that is not referring to *this* block then all predecessors
350                         // must have that local available.
351                         VALIDATE((local, block, block->predecessors[k]), prevNode);
352                         switch (prevNode->op()) {
353                         case GetLocal:
354                         case Flush:
355                         case PhantomLocal:
356                             prevNode = prevNode->child1().node();
357                             break;
358                         default:
359                             break;
360                         }
361                         if (node->shouldGenerate()) {
362                             VALIDATE((local, block->predecessors[k], prevNode),
363                                      prevNode->shouldGenerate());
364                         }
365                         VALIDATE(
366                             (local, block->predecessors[k], prevNode),
367                             prevNode->op() == SetLocal
368                             || prevNode->op() == SetArgument
369                             || prevNode->op() == Phi);
370                         if (prevNode == edge.node()) {
371                             found = true;
372                             break;
373                         }
374                         // At this point it cannot refer into this block.
375                         VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
376                     }
377                     
378                     VALIDATE((node, edge), found);
379                 }
380             }
381             
382             Operands<size_t> getLocalPositions(
383                 block->variablesAtHead.numberOfArguments(),
384                 block->variablesAtHead.numberOfLocals());
385             Operands<size_t> setLocalPositions(
386                 block->variablesAtHead.numberOfArguments(),
387                 block->variablesAtHead.numberOfLocals());
388             
389             for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
390                 VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData(m_graph));
391                 if (m_graph.m_form == ThreadedCPS)
392                     VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData(m_graph));
393                 
394                 getLocalPositions.argument(i) = notSet;
395                 setLocalPositions.argument(i) = notSet;
396             }
397             for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
398                 VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData(m_graph));
399                 if (m_graph.m_form == ThreadedCPS)
400                     VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData(m_graph));
401
402                 getLocalPositions.local(i) = notSet;
403                 setLocalPositions.local(i) = notSet;
404             }
405             
406             for (size_t i = 0; i < block->size(); ++i) {
407                 Node* node = block->at(i);
408                 ASSERT(nodesInThisBlock.contains(node));
409                 VALIDATE((node), node->op() != Phi);
410                 VALIDATE((node), node->origin.forExit.isSet());
411                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
412                     Edge edge = m_graph.child(node, j);
413                     if (!edge)
414                         continue;
415                     VALIDATE((node, edge), nodesInThisBlock.contains(edge.node()));
416                     switch (node->op()) {
417                     case PhantomLocal:
418                     case GetLocal:
419                     case Flush:
420                         break;
421                     default:
422                         VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
423                         break;
424                     }
425                 }
426                 
427                 switch (node->op()) {
428                 case Phi:
429                 case Upsilon:
430                 case CheckInBounds:
431                 case PhantomNewObject:
432                 case PhantomNewFunction:
433                 case PhantomCreateActivation:
434                 case GetMyArgumentByVal:
435                 case PutHint:
436                 case CheckStructureImmediate:
437                 case MaterializeNewObject:
438                 case MaterializeCreateActivation:
439                 case PutStack:
440                 case KillStack:
441                 case GetStack:
442                     VALIDATE((node), !"unexpected node type in CPS");
443                     break;
444                 case Phantom:
445                     VALIDATE((node), m_graph.m_fixpointState != FixpointNotConverged);
446                     break;
447                 default:
448                     break;
449                 }
450                 
451                 if (!node->shouldGenerate())
452                     continue;
453                 switch (node->op()) {
454                 case GetLocal:
455                     // Ignore GetLocal's that we know to be dead, but that the graph
456                     // doesn't yet know to be dead.
457                     if (!m_myRefCounts.get(node))
458                         break;
459                     if (m_graph.m_form == ThreadedCPS) {
460                         VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet);
461                         VALIDATE((node, block), !!node->child1());
462                     }
463                     getLocalPositions.operand(node->local()) = i;
464                     break;
465                 case SetLocal:
466                     // Only record the first SetLocal. There may be multiple SetLocals
467                     // because of flushing.
468                     if (setLocalPositions.operand(node->local()) != notSet)
469                         break;
470                     setLocalPositions.operand(node->local()) = i;
471                     break;
472                 case SetArgument:
473                     // This acts like a reset. It's ok to have a second GetLocal for a local in the same
474                     // block if we had a SetArgument for that local.
475                     getLocalPositions.operand(node->local()) = notSet;
476                     setLocalPositions.operand(node->local()) = notSet;
477                     break;
478                 default:
479                     break;
480                 }
481             }
482             
483             if (m_graph.m_form == LoadStore)
484                 continue;
485             
486             for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
487                 checkOperand(
488                     block, getLocalPositions, setLocalPositions, virtualRegisterForArgument(i));
489             }
490             for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
491                 checkOperand(
492                     block, getLocalPositions, setLocalPositions, virtualRegisterForLocal(i));
493             }
494         }
495     }
496     
497     void validateSSA()
498     {
499         // FIXME: Add more things here.
500         // https://bugs.webkit.org/show_bug.cgi?id=123471
501         
502         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
503             BasicBlock* block = m_graph.block(blockIndex);
504             if (!block)
505                 continue;
506             
507             VALIDATE((block), block->phis.isEmpty());
508             
509             unsigned nodeIndex = 0;
510             for (; nodeIndex < block->size() && !block->at(nodeIndex)->origin.forExit.isSet(); nodeIndex++) { }
511             
512             VALIDATE((block), nodeIndex < block->size());
513             
514             for (; nodeIndex < block->size(); nodeIndex++)
515                 VALIDATE((block->at(nodeIndex)), block->at(nodeIndex)->origin.forExit.isSet());
516             
517             for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
518                 Node* node = block->at(nodeIndex);
519                 switch (node->op()) {
520                 case Phi:
521                     VALIDATE((node), !node->origin.forExit.isSet());
522                     break;
523                     
524                 case GetLocal:
525                 case SetLocal:
526                 case GetLocalUnlinked:
527                 case SetArgument:
528                 case Phantom:
529                     VALIDATE((node), !"bad node type for SSA");
530                     break;
531                     
532                 default:
533                     // FIXME: Add more things here.
534                     // https://bugs.webkit.org/show_bug.cgi?id=123471
535                     break;
536                 }
537             }
538         }
539     }
540
541     void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge)
542     {
543         if (!edge->hasDoubleResult())
544             return;
545
546         if (m_graph.m_planStage < PlanStage::AfterFixup)
547             VALIDATE((node, edge), edge.useKind() == UntypedUse);
548         else
549             VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse);
550     }
551
552     void checkOperand(
553         BasicBlock* block, Operands<size_t>& getLocalPositions,
554         Operands<size_t>& setLocalPositions, VirtualRegister operand)
555     {
556         if (getLocalPositions.operand(operand) == notSet)
557             return;
558         if (setLocalPositions.operand(operand) == notSet)
559             return;
560         
561         VALIDATE(
562             (block->at(getLocalPositions.operand(operand)),
563              block->at(setLocalPositions.operand(operand)),
564              block),
565             getLocalPositions.operand(operand) < setLocalPositions.operand(operand));
566     }
567     
568     void reportValidationContext(Node* node)
569     {
570         dataLogF("@%u", node->index());
571     }
572     
573     void reportValidationContext(BasicBlock* block)
574     {
575         dataLog("Block ", *block);
576     }
577     
578     void reportValidationContext(Node* node, Edge edge)
579     {
580         dataLog(node, " -> ", edge);
581     }
582     
583     void reportValidationContext(VirtualRegister local, BasicBlock* block)
584     {
585         if (!block) {
586             dataLog(local, " in null Block ");
587             return;
588         }
589
590         dataLog(local, " in Block ", *block);
591     }
592     
593     void reportValidationContext(
594         VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock)
595     {
596         dataLog(local, " in Block ", *sourceBlock, " -> ", *destinationBlock);
597     }
598     
599     void reportValidationContext(
600         VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode)
601     {
602         dataLog(prevNode, " for ", local, " in Block ", *sourceBlock);
603     }
604     
605     void reportValidationContext(Node* node, BasicBlock* block)
606     {
607         dataLog(node, " in Block ", *block);
608     }
609     
610     void reportValidationContext(Node* node, Node* node2, BasicBlock* block)
611     {
612         dataLog(node, " and ", node2, " in Block ", *block);
613     }
614     
615     void reportValidationContext(
616         Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge)
617     {
618         dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge);
619     }
620     
621     void dumpGraphIfAppropriate()
622     {
623         if (m_graphDumpMode == DontDumpGraph)
624             return;
625         dataLog("\n");
626         if (!m_graphDumpBeforePhase.isNull()) {
627             dataLog("Before phase:\n");
628             dataLog(m_graphDumpBeforePhase);
629         }
630         dataLog("At time of failure:\n");
631         m_graph.dump();
632     }
633 };
634
635 void validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase)
636 {
637     Validate validationObject(graph, graphDumpMode, graphDumpBeforePhase);
638     validationObject.validate();
639 }
640
641 } } // namespace JSC::DFG
642
643 #endif // ENABLE(DFG_JIT)
644