1/*
2 * Copyright (C) 2012-2016 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 "DFGClobberize.h"
33#include "DFGClobbersExitState.h"
34#include "DFGMayExit.h"
35#include "JSCInlines.h"
36#include <wtf/Assertions.h>
37
38namespace JSC { namespace DFG {
39
40namespace {
41
42class Validate {
43public:
44 Validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase)
45 : m_graph(graph)
46 , m_graphDumpMode(graphDumpMode)
47 , m_graphDumpBeforePhase(graphDumpBeforePhase)
48 {
49 }
50
51 #define VALIDATE(context, assertion) do { \
52 if (!(assertion)) { \
53 startCrashing(); \
54 dataLogF("\n\n\nAt "); \
55 reportValidationContext context; \
56 dataLogF(": validation failed: %s (%s:%d).\n", #assertion, __FILE__, __LINE__); \
57 dumpGraphIfAppropriate(); \
58 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
59 CRASH(); \
60 } \
61 } while (0)
62
63 #define V_EQUAL(context, left, right) do { \
64 if (left != right) { \
65 startCrashing(); \
66 dataLogF("\n\n\nAt "); \
67 reportValidationContext context; \
68 dataLogF(": validation failed: (%s = ", #left); \
69 dataLog(left); \
70 dataLogF(") == (%s = ", #right); \
71 dataLog(right); \
72 dataLogF(") (%s:%d).\n", __FILE__, __LINE__); \
73 dumpGraphIfAppropriate(); \
74 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \
75 CRASH(); \
76 } \
77 } while (0)
78
79 #define notSet (static_cast<size_t>(-1))
80
81 void validate()
82 {
83 // NB. This code is not written for performance, since it is not intended to run
84 // in release builds.
85
86 VALIDATE((m_graph.block(0)), m_graph.isRoot(m_graph.block(0)));
87 VALIDATE((m_graph.block(0)), m_graph.block(0) == m_graph.m_roots[0]);
88
89 for (BasicBlock* block : m_graph.m_roots)
90 VALIDATE((block), block->predecessors.isEmpty());
91
92 // Validate that all local variables at the head of all entrypoints are dead.
93 for (BasicBlock* entrypoint : m_graph.m_roots) {
94 for (unsigned i = 0; i < entrypoint->variablesAtHead.numberOfLocals(); ++i)
95 V_EQUAL((virtualRegisterForLocal(i), entrypoint), static_cast<Node*>(nullptr), entrypoint->variablesAtHead.local(i));
96 }
97
98 // Validate ref counts and uses.
99 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
100 BasicBlock* block = m_graph.block(blockIndex);
101 if (!block)
102 continue;
103 VALIDATE((block), block->isReachable);
104 for (size_t i = 0; i < block->numNodes(); ++i)
105 m_myRefCounts.add(block->node(i), 0);
106 }
107 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
108 BasicBlock* block = m_graph.block(blockIndex);
109 if (!block)
110 continue;
111 for (size_t i = 0; i < block->numNodes(); ++i) {
112 Node* node = block->node(i);
113 m_acceptableNodes.add(node);
114 if (!node->shouldGenerate())
115 continue;
116 if (node->op() == Upsilon) {
117 VALIDATE((node), m_graph.m_form == SSA);
118 if (node->phi()->shouldGenerate())
119 m_myRefCounts.find(node)->value++;
120 }
121 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
122 // Phi children in LoadStore form are invalid.
123 if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
124 continue;
125
126 Edge edge = m_graph.child(node, j);
127 if (!edge)
128 continue;
129
130 m_myRefCounts.find(edge.node())->value++;
131
132 validateEdgeWithDoubleResultIfNecessary(node, edge);
133 VALIDATE((node, edge), edge->hasInt52Result() == (edge.useKind() == Int52RepUse));
134
135 if (m_graph.m_form == SSA) {
136 // In SSA, all edges must hasResult().
137 VALIDATE((node, edge), edge->hasResult());
138 continue;
139 }
140
141 // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult().
142 switch (node->op()) {
143 case Flush:
144 case GetLocal:
145 VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
146 VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
147 break;
148 case PhantomLocal:
149 VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
150 VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
151 VALIDATE((node, edge), edge->op() != SetLocal);
152 break;
153 case Phi:
154 VALIDATE((node, edge), edge->hasVariableAccessData(m_graph));
155 if (m_graph.m_unificationState == LocallyUnified)
156 break;
157 VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
158 break;
159 default:
160 VALIDATE((node, edge), edge->hasResult());
161 break;
162 }
163 }
164 }
165 }
166
167 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
168 BasicBlock* block = m_graph.block(blockIndex);
169 if (!block)
170 continue;
171 for (size_t i = 0; i < block->numNodes(); ++i) {
172 Node* node = block->node(i);
173 if (m_graph.m_refCountState == ExactRefCount)
174 V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount());
175 }
176
177 bool foundTerminal = false;
178 for (size_t i = 0 ; i < block->size(); ++i) {
179 Node* node = block->at(i);
180 if (node->isTerminal()) {
181 foundTerminal = true;
182 for (size_t j = i + 1; j < block->size(); ++j) {
183 node = block->at(j);
184 VALIDATE((node), node->op() == Phantom || node->op() == PhantomLocal || node->op() == Flush || node->op() == Check);
185 m_graph.doToChildren(
186 node,
187 [&] (Edge edge) {
188 VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind()));
189 });
190 }
191 break;
192 }
193 }
194 VALIDATE((block), foundTerminal);
195
196 for (size_t i = 0; i < block->size(); ++i) {
197 Node* node = block->at(i);
198
199 VALIDATE((node), node->origin.isSet());
200 VALIDATE((node), node->origin.semantic.isSet() == node->origin.forExit.isSet());
201 VALIDATE((node), !(!node->origin.forExit.isSet() && node->origin.exitOK));
202 VALIDATE((node), !(mayExit(m_graph, node) == Exits && !node->origin.exitOK));
203
204 if (i) {
205 Node* previousNode = block->at(i - 1);
206 VALIDATE(
207 (node),
208 !clobbersExitState(m_graph, previousNode)
209 || !node->origin.exitOK
210 || node->op() == ExitOK
211 || node->origin.forExit != previousNode->origin.forExit);
212 VALIDATE(
213 (node),
214 !(!previousNode->origin.exitOK && node->origin.exitOK)
215 || node->op() == ExitOK
216 || node->origin.forExit != previousNode->origin.forExit);
217 }
218
219 VALIDATE((node), !node->hasStructure() || !!node->structure().get());
220 VALIDATE((node), !node->hasCellOperand() || node->cellOperand()->value().isCell());
221 VALIDATE((node), !node->hasCellOperand() || !!node->cellOperand()->value());
222
223 if (!(node->flags() & NodeHasVarArgs)) {
224 if (!node->child2())
225 VALIDATE((node), !node->child3());
226 if (!node->child1())
227 VALIDATE((node), !node->child2());
228 }
229
230 switch (node->op()) {
231 case Identity:
232 case IdentityWithProfile:
233 VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result()));
234 break;
235 case SetLocal:
236 case PutStack:
237 case Upsilon:
238 VALIDATE((node), !!node->child1());
239 switch (node->child1().useKind()) {
240 case UntypedUse:
241 case CellUse:
242 case KnownCellUse:
243 case Int32Use:
244 case KnownInt32Use:
245 case Int52RepUse:
246 case DoubleRepUse:
247 case BooleanUse:
248 case KnownBooleanUse:
249 break;
250 default:
251 VALIDATE((node), !"Bad use kind");
252 break;
253 }
254 break;
255 case MakeRope:
256 case ValueAdd:
257 case ValueSub:
258 case ValueMul:
259 case ValueDiv:
260 case ValueMod:
261 case ArithAdd:
262 case ArithSub:
263 case ArithMul:
264 case ArithIMul:
265 case ArithDiv:
266 case ArithMod:
267 case ArithMin:
268 case ArithMax:
269 case ArithPow:
270 case CompareLess:
271 case CompareLessEq:
272 case CompareGreater:
273 case CompareGreaterEq:
274 case CompareBelow:
275 case CompareBelowEq:
276 case CompareEq:
277 case CompareStrictEq:
278 case SameValue:
279 case StrCat:
280 VALIDATE((node), !!node->child1());
281 VALIDATE((node), !!node->child2());
282 break;
283 case CompareEqPtr:
284 VALIDATE((node), !!node->child1());
285 VALIDATE((node), !!node->cellOperand()->value() && node->cellOperand()->value().isCell());
286 break;
287 case CheckStructureOrEmpty:
288 VALIDATE((node), is64Bit());
289 VALIDATE((node), !!node->child1());
290 VALIDATE((node), node->child1().useKind() == CellUse);
291 break;
292 case CheckStructure:
293 case StringFromCharCode:
294 VALIDATE((node), !!node->child1());
295 break;
296 case PutStructure:
297 VALIDATE((node), !node->transition()->previous->dfgShouldWatch());
298 break;
299 case MultiPutByOffset:
300 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
301 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
302 if (variant.kind() != PutByIdVariant::Transition)
303 continue;
304 VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch());
305 }
306 break;
307 case MaterializeNewObject:
308 for (RegisteredStructure structure : node->structureSet()) {
309 // This only supports structures that are JSFinalObject or JSArray.
310 VALIDATE(
311 (node),
312 structure->classInfo() == JSFinalObject::info()
313 || structure->classInfo() == JSArray::info());
314
315 // We only support certain indexing shapes.
316 VALIDATE((node), !hasAnyArrayStorage(structure->indexingType()));
317 }
318 break;
319 case DoubleConstant:
320 case Int52Constant:
321 VALIDATE((node), node->isNumberConstant());
322 break;
323 case GetByOffset:
324 case PutByOffset:
325 // FIXME: We should be able to validate that GetByOffset and PutByOffset are
326 // using the same object for storage and base. I think this means finally
327 // splitting these nodes into two node types, one for inline and one for
328 // out-of-line. The out-of-line one will require that the first node is storage,
329 // while the inline one will not take a storage child at all.
330 // https://bugs.webkit.org/show_bug.cgi?id=159602
331 break;
332 case HasOwnProperty: {
333 VALIDATE((node), !!m_graph.m_vm.hasOwnPropertyCache());
334 break;
335 }
336 case GetVectorLength: {
337 Array::Type type = node->arrayMode().type();
338 VALIDATE((node), type == Array::ArrayStorage || type == Array::SlowPutArrayStorage);
339 break;
340 }
341 case CPUIntrinsic: {
342 switch (node->intrinsic()) {
343 case CPUMfenceIntrinsic:
344 case CPURdtscIntrinsic:
345 case CPUCpuidIntrinsic:
346 case CPUPauseIntrinsic:
347 break;
348 default:
349 VALIDATE((node), false);
350 break;
351 }
352 break;
353 }
354 case GetArgumentCountIncludingThis: {
355 if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
356 VALIDATE((node), inlineCallFrame->isVarargs());
357 break;
358 }
359 case NewArray:
360 VALIDATE((node), node->vectorLengthHint() >= node->numChildren());
361 break;
362 case NewArrayBuffer:
363 VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length());
364 break;
365 default:
366 break;
367 }
368 }
369 }
370
371 switch (m_graph.m_form) {
372 case LoadStore:
373 case ThreadedCPS:
374 validateCPS();
375 break;
376
377 case SSA:
378 validateSSA();
379 break;
380 }
381
382 // Validate clobbered states.
383 struct DefLambdaAdaptor {
384 Function<void(PureValue)> pureValue;
385 Function<void(HeapLocation, LazyNode)> locationAndNode;
386
387 void operator()(PureValue value) const
388 {
389 pureValue(value);
390 }
391
392 void operator()(HeapLocation location, LazyNode node) const
393 {
394 locationAndNode(location, node);
395 }
396 };
397 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
398 for (Node* node : *block) {
399 clobberize(m_graph, node,
400 [&] (AbstractHeap) { },
401 [&] (AbstractHeap heap)
402 {
403 // CSE assumes that HEAP TOP is never written.
404 // If this assumption is weakened, you need to update clobbering
405 // in CSE accordingly.
406 if (heap.kind() == Stack)
407 VALIDATE((node), !heap.payload().isTop());
408 },
409 DefLambdaAdaptor {
410 [&] (PureValue) { },
411 [&] (HeapLocation location, LazyNode)
412 {
413 VALIDATE((node), location.heap().kind() != SideState);
414
415 // More specific kinds should be used instead.
416 VALIDATE((node), location.heap().kind() != World);
417 VALIDATE((node), location.heap().kind() != Heap);
418 }
419 });
420 }
421 }
422
423 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
424 // We expect the predecessor list to be de-duplicated.
425 HashSet<BasicBlock*> predecessors;
426 for (BasicBlock* predecessor : block->predecessors)
427 predecessors.add(predecessor);
428 VALIDATE((block), predecessors.size() == block->predecessors.size());
429 }
430 }
431
432private:
433 Graph& m_graph;
434 GraphDumpMode m_graphDumpMode;
435 CString m_graphDumpBeforePhase;
436
437 HashMap<Node*, unsigned> m_myRefCounts;
438 HashSet<Node*> m_acceptableNodes;
439
440 void validateCPS()
441 {
442 VALIDATE((), !m_graph.m_rootToArguments.isEmpty()); // We should have at least one root.
443 VALIDATE((), m_graph.m_rootToArguments.size() == m_graph.m_roots.size());
444 for (BasicBlock* root : m_graph.m_rootToArguments.keys())
445 VALIDATE((), m_graph.m_roots.contains(root));
446
447 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
448 BasicBlock* block = m_graph.block(blockIndex);
449 if (!block)
450 continue;
451
452 HashSet<Node*> phisInThisBlock;
453 HashSet<Node*> nodesInThisBlock;
454
455 for (size_t i = 0; i < block->numNodes(); ++i) {
456 Node* node = block->node(i);
457 nodesInThisBlock.add(node);
458 if (block->isPhiIndex(i))
459 phisInThisBlock.add(node);
460 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
461 Edge edge = m_graph.child(node, j);
462 if (!edge)
463 continue;
464 VALIDATE((node, edge), m_acceptableNodes.contains(edge.node()));
465 }
466 }
467
468 {
469 HashSet<Node*> seenNodes;
470 for (size_t i = 0; i < block->size(); ++i) {
471 Node* node = block->at(i);
472 m_graph.doToChildren(node, [&] (const Edge& edge) {
473 Node* child = edge.node();
474 VALIDATE((node), block->isInPhis(child) || seenNodes.contains(child));
475 });
476 seenNodes.add(node);
477 }
478 }
479
480 for (size_t i = 0; i < block->phis.size(); ++i) {
481 Node* node = block->phis[i];
482 ASSERT(phisInThisBlock.contains(node));
483 VALIDATE((node), node->op() == Phi);
484 VirtualRegister local = node->local();
485 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
486 // Phi children in LoadStore form are invalid.
487 if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
488 continue;
489
490 Edge edge = m_graph.child(node, j);
491 if (!edge)
492 continue;
493
494 VALIDATE(
495 (node, edge),
496 edge->op() == SetLocal
497 || edge->op() == SetArgumentDefinitely
498 || edge->op() == SetArgumentMaybe
499 || edge->op() == Phi);
500
501 if (phisInThisBlock.contains(edge.node()))
502 continue;
503
504 if (nodesInThisBlock.contains(edge.node())) {
505 VALIDATE(
506 (node, edge),
507 edge->op() == SetLocal
508 || edge->op() == SetArgumentDefinitely
509 || edge->op() == SetArgumentMaybe);
510
511 continue;
512 }
513
514 // There must exist a predecessor block that has this node index in
515 // its tail variables.
516 bool found = false;
517 for (unsigned k = 0; k < block->predecessors.size(); ++k) {
518 BasicBlock* prevBlock = block->predecessors[k];
519 VALIDATE((block->predecessors[k]), prevBlock);
520 Node* prevNode = prevBlock->variablesAtTail.operand(local);
521 // If we have a Phi that is not referring to *this* block then all predecessors
522 // must have that local available.
523 VALIDATE((local, block, block->predecessors[k]), prevNode);
524 switch (prevNode->op()) {
525 case GetLocal:
526 case Flush:
527 case PhantomLocal:
528 prevNode = prevNode->child1().node();
529 break;
530 default:
531 break;
532 }
533 if (node->shouldGenerate()) {
534 VALIDATE((local, block->predecessors[k], prevNode),
535 prevNode->shouldGenerate());
536 }
537 VALIDATE(
538 (local, block->predecessors[k], prevNode),
539 prevNode->op() == SetLocal
540 || prevNode->op() == SetArgumentDefinitely
541 || prevNode->op() == SetArgumentMaybe
542 || prevNode->op() == Phi);
543 if (prevNode == edge.node()) {
544 found = true;
545 break;
546 }
547 // At this point it cannot refer into this block.
548 VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
549 }
550
551 VALIDATE((node, edge), found);
552 }
553 }
554
555 Operands<size_t> getLocalPositions(
556 block->variablesAtHead.numberOfArguments(),
557 block->variablesAtHead.numberOfLocals());
558 Operands<size_t> setLocalPositions(
559 block->variablesAtHead.numberOfArguments(),
560 block->variablesAtHead.numberOfLocals());
561
562 for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
563 VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->accessesStack(m_graph));
564 if (m_graph.m_form == ThreadedCPS)
565 VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->accessesStack(m_graph));
566
567 getLocalPositions.argument(i) = notSet;
568 setLocalPositions.argument(i) = notSet;
569 }
570 for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
571 VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->accessesStack(m_graph));
572 if (m_graph.m_form == ThreadedCPS)
573 VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->accessesStack(m_graph));
574
575 getLocalPositions.local(i) = notSet;
576 setLocalPositions.local(i) = notSet;
577 }
578
579 for (size_t i = 0; i < block->size(); ++i) {
580 Node* node = block->at(i);
581 ASSERT(nodesInThisBlock.contains(node));
582 VALIDATE((node), node->op() != Phi);
583 VALIDATE((node), node->origin.forExit.isSet());
584 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
585 Edge edge = m_graph.child(node, j);
586 if (!edge)
587 continue;
588 VALIDATE((node, edge), nodesInThisBlock.contains(edge.node()));
589 switch (node->op()) {
590 case PhantomLocal:
591 case GetLocal:
592 case Flush:
593 break;
594 default:
595 VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
596 break;
597 }
598 }
599
600 switch (node->op()) {
601 case Phi:
602 case Upsilon:
603 case CheckInBounds:
604 case PhantomNewObject:
605 case PhantomNewFunction:
606 case PhantomNewGeneratorFunction:
607 case PhantomNewAsyncFunction:
608 case PhantomNewAsyncGeneratorFunction:
609 case PhantomCreateActivation:
610 case PhantomNewRegexp:
611 case GetMyArgumentByVal:
612 case GetMyArgumentByValOutOfBounds:
613 case PutHint:
614 case CheckStructureImmediate:
615 case MaterializeCreateActivation:
616 case PutStack:
617 case KillStack:
618 case GetStack:
619 case EntrySwitch:
620 case InitializeEntrypointArguments:
621 VALIDATE((node), !"unexpected node type in CPS");
622 break;
623 case MaterializeNewObject: {
624 // CPS only allows array lengths to be constant. This constraint only exists
625 // because we don't have DFG support for anything more and we don't need any
626 // other kind of support for now.
627 ObjectMaterializationData& data = node->objectMaterializationData();
628 for (unsigned i = data.m_properties.size(); i--;) {
629 PromotedLocationDescriptor descriptor = data.m_properties[i];
630 Edge edge = m_graph.varArgChild(node, 1 + i);
631 switch (descriptor.kind()) {
632 case PublicLengthPLoc:
633 case VectorLengthPLoc:
634 VALIDATE((node, edge), edge->isInt32Constant());
635 break;
636 default:
637 break;
638 }
639 }
640
641 // CPS only allows one structure.
642 VALIDATE((node), node->structureSet().size() == 1);
643
644 // CPS disallows int32 and double arrays. Those require weird type checks and
645 // conversions. They are not needed in the DFG right now. We should add support
646 // for these if the DFG ever needs it.
647 for (RegisteredStructure structure : node->structureSet()) {
648 VALIDATE((node), !hasInt32(structure->indexingType()));
649 VALIDATE((node), !hasDouble(structure->indexingType()));
650 }
651 break;
652 }
653 case Phantom:
654 VALIDATE((node), m_graph.m_fixpointState != FixpointNotConverged);
655 break;
656 default:
657 break;
658 }
659
660 if (!node->shouldGenerate())
661 continue;
662 switch (node->op()) {
663 case GetLocal:
664 // Ignore GetLocal's that we know to be dead, but that the graph
665 // doesn't yet know to be dead.
666 if (!m_myRefCounts.get(node))
667 break;
668 if (m_graph.m_form == ThreadedCPS) {
669 VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet);
670 VALIDATE((node, block), !!node->child1());
671 VALIDATE((node, block), node->child1()->op() == SetArgumentDefinitely || node->child1()->op() == Phi);
672 }
673 getLocalPositions.operand(node->local()) = i;
674 break;
675 case SetLocal:
676 // Only record the first SetLocal. There may be multiple SetLocals
677 // because of flushing.
678 if (setLocalPositions.operand(node->local()) != notSet)
679 break;
680 setLocalPositions.operand(node->local()) = i;
681 break;
682 case SetArgumentDefinitely:
683 // This acts like a reset. It's ok to have a second GetLocal for a local in the same
684 // block if we had a SetArgumentDefinitely for that local.
685 getLocalPositions.operand(node->local()) = notSet;
686 setLocalPositions.operand(node->local()) = notSet;
687 break;
688 case SetArgumentMaybe:
689 break;
690 case Flush:
691 case PhantomLocal:
692 if (m_graph.m_form == ThreadedCPS) {
693 VALIDATE((node, block),
694 node->child1()->op() == Phi
695 || node->child1()->op() == SetLocal
696 || node->child1()->op() == SetArgumentDefinitely
697 || node->child1()->op() == SetArgumentMaybe);
698 if (node->op() == PhantomLocal)
699 VALIDATE((node, block), node->child1()->op() != SetArgumentMaybe);
700 }
701 break;
702 default:
703 break;
704 }
705 }
706
707 if (m_graph.m_form == LoadStore)
708 continue;
709
710 for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
711 checkOperand(
712 block, getLocalPositions, setLocalPositions, virtualRegisterForArgument(i));
713 }
714 for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
715 checkOperand(
716 block, getLocalPositions, setLocalPositions, virtualRegisterForLocal(i));
717 }
718 }
719
720 if (m_graph.m_form == ThreadedCPS) {
721 Vector<Node*> worklist;
722 HashSet<Node*> seen;
723 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
724 for (Node* node : *block) {
725 if (node->op() == GetLocal || node->op() == PhantomLocal) {
726 worklist.append(node);
727 auto addResult = seen.add(node);
728 VALIDATE((node, block), addResult.isNewEntry);
729 }
730 }
731 }
732
733 while (worklist.size()) {
734 Node* node = worklist.takeLast();
735 switch (node->op()) {
736 case PhantomLocal:
737 case GetLocal: {
738 Node* child = node->child1().node();
739 if (seen.add(child).isNewEntry)
740 worklist.append(child);
741 break;
742 }
743 case Phi: {
744 for (unsigned i = 0; i < m_graph.numChildren(node); ++i) {
745 Edge edge = m_graph.child(node, i);
746 if (!edge)
747 continue;
748 if (seen.add(edge.node()).isNewEntry)
749 worklist.append(edge.node());
750 }
751 break;
752 }
753 case SetLocal:
754 case SetArgumentDefinitely:
755 break;
756 case SetArgumentMaybe:
757 VALIDATE((node), !"Should not reach SetArgumentMaybe. GetLocal that has data flow that reaches a SetArgumentMaybe is invalid IR.");
758 break;
759 default:
760 VALIDATE((node), !"Unexecpted node type.");
761 break;
762 }
763 }
764 }
765 }
766
767 void validateSSA()
768 {
769 // FIXME: Add more things here.
770 // https://bugs.webkit.org/show_bug.cgi?id=123471
771
772 VALIDATE((), m_graph.m_roots.size() == 1);
773 VALIDATE((), m_graph.m_roots[0] == m_graph.block(0));
774 VALIDATE((), !m_graph.m_argumentFormats.isEmpty()); // We always have at least one entrypoint.
775 VALIDATE((), m_graph.m_rootToArguments.isEmpty()); // This is only used in CPS.
776
777 for (unsigned entrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys())
778 VALIDATE((), entrypointIndex > 0); // By convention, 0 is the entrypoint index for the op_enter entrypoint, which can not be in a catch.
779
780 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
781 BasicBlock* block = m_graph.block(blockIndex);
782 if (!block)
783 continue;
784
785 VALIDATE((block), block->phis.isEmpty());
786
787 bool didSeeExitOK = false;
788 bool isOSRExited = false;
789
790 for (auto* node : *block) {
791 didSeeExitOK |= node->origin.exitOK;
792 switch (node->op()) {
793 case Phi:
794 // Phi cannot exit, and it would be wrong to hoist anything to the Phi that could
795 // exit.
796 VALIDATE((node), !node->origin.exitOK);
797
798 // It never makes sense to have exitOK anywhere in the block before a Phi. It's only
799 // OK to exit after all Phis are done.
800 VALIDATE((node), !didSeeExitOK);
801 break;
802
803 case GetLocal:
804 case SetLocal:
805 case SetArgumentDefinitely:
806 case SetArgumentMaybe:
807 case Phantom:
808 VALIDATE((node), !"bad node type for SSA");
809 break;
810
811 default:
812 // FIXME: Add more things here.
813 // https://bugs.webkit.org/show_bug.cgi?id=123471
814 break;
815 }
816
817 if (isOSRExited)
818 continue;
819 switch (node->op()) {
820 case PhantomNewObject:
821 case PhantomNewFunction:
822 case PhantomNewGeneratorFunction:
823 case PhantomNewAsyncFunction:
824 case PhantomNewAsyncGeneratorFunction:
825 case PhantomCreateActivation:
826 case PhantomDirectArguments:
827 case PhantomCreateRest:
828 case PhantomClonedArguments:
829 case PhantomNewRegexp:
830 case MovHint:
831 case Upsilon:
832 case ForwardVarargs:
833 case CallForwardVarargs:
834 case TailCallForwardVarargs:
835 case TailCallForwardVarargsInlinedCaller:
836 case ConstructForwardVarargs:
837 case GetMyArgumentByVal:
838 case GetMyArgumentByValOutOfBounds:
839 break;
840
841 case Check:
842 case CheckVarargs:
843 // FIXME: This is probably not correct.
844 break;
845
846 case PutHint:
847 VALIDATE((node), node->child1()->isPhantomAllocation());
848 break;
849
850 case PhantomSpread:
851 VALIDATE((node), m_graph.m_form == SSA);
852 // We currently support PhantomSpread over PhantomCreateRest and PhantomNewArrayBuffer.
853 VALIDATE((node), node->child1()->op() == PhantomCreateRest || node->child1()->op() == PhantomNewArrayBuffer);
854 break;
855
856 case PhantomNewArrayWithSpread: {
857 VALIDATE((node), m_graph.m_form == SSA);
858 BitVector* bitVector = node->bitVector();
859 for (unsigned i = 0; i < node->numChildren(); i++) {
860 Node* child = m_graph.varArgChild(node, i).node();
861 if (bitVector->get(i)) {
862 // We currently support PhantomSpread over PhantomCreateRest and PhantomNewArrayBuffer.
863 VALIDATE((node), child->op() == PhantomSpread);
864 } else
865 VALIDATE((node), !child->isPhantomAllocation());
866 }
867 break;
868 }
869
870 case PhantomNewArrayBuffer:
871 VALIDATE((node), m_graph.m_form == SSA);
872 VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length());
873 break;
874
875 case NewArrayWithSpread: {
876 BitVector* bitVector = node->bitVector();
877 for (unsigned i = 0; i < node->numChildren(); i++) {
878 Node* child = m_graph.varArgChild(node, i).node();
879 if (child->isPhantomAllocation()) {
880 VALIDATE((node), bitVector->get(i));
881 VALIDATE((node), m_graph.m_form == SSA);
882 VALIDATE((node), child->op() == PhantomSpread);
883 }
884 }
885 break;
886 }
887
888 case Spread:
889 VALIDATE((node), !node->child1()->isPhantomAllocation() || node->child1()->op() == PhantomCreateRest || node->child1()->op() == PhantomNewArrayBuffer);
890 break;
891
892 case EntrySwitch:
893 VALIDATE((node), node->entrySwitchData()->cases.size() == m_graph.m_numberOfEntrypoints);
894 break;
895
896 case InitializeEntrypointArguments:
897 VALIDATE((node), node->entrypointIndex() < m_graph.m_numberOfEntrypoints);
898 break;
899
900 default:
901 m_graph.doToChildren(
902 node,
903 [&] (const Edge& edge) {
904 VALIDATE((node), !edge->isPhantomAllocation());
905 });
906 break;
907 }
908 isOSRExited |= node->isPseudoTerminal();
909 }
910 }
911 }
912
913 void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge)
914 {
915 if (!edge->hasDoubleResult())
916 return;
917
918 if (m_graph.m_planStage < PlanStage::AfterFixup)
919 return;
920
921 VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepAnyIntUse);
922 }
923
924 void checkOperand(
925 BasicBlock* block, Operands<size_t>& getLocalPositions,
926 Operands<size_t>& setLocalPositions, VirtualRegister operand)
927 {
928 if (getLocalPositions.operand(operand) == notSet)
929 return;
930 if (setLocalPositions.operand(operand) == notSet)
931 return;
932
933 VALIDATE(
934 (block->at(getLocalPositions.operand(operand)),
935 block->at(setLocalPositions.operand(operand)),
936 block),
937 getLocalPositions.operand(operand) < setLocalPositions.operand(operand));
938 }
939
940 void reportValidationContext() { }
941
942 void reportValidationContext(Node* node)
943 {
944 dataLogF("@%u", node->index());
945 }
946
947 void reportValidationContext(BasicBlock* block)
948 {
949 dataLog("Block ", *block);
950 }
951
952 void reportValidationContext(Node* node, Edge edge)
953 {
954 dataLog(node, " -> ", edge);
955 }
956
957 void reportValidationContext(VirtualRegister local, BasicBlock* block)
958 {
959 if (!block) {
960 dataLog(local, " in null Block ");
961 return;
962 }
963
964 dataLog(local, " in Block ", *block);
965 }
966
967 void reportValidationContext(
968 VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock)
969 {
970 dataLog(local, " in Block ", *sourceBlock, " -> ", *destinationBlock);
971 }
972
973 void reportValidationContext(
974 VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode)
975 {
976 dataLog(prevNode, " for ", local, " in Block ", *sourceBlock);
977 }
978
979 void reportValidationContext(Node* node, BasicBlock* block)
980 {
981 dataLog(node, " in Block ", *block);
982 }
983
984 void reportValidationContext(Node* node, Node* node2, BasicBlock* block)
985 {
986 dataLog(node, " and ", node2, " in Block ", *block);
987 }
988
989 void reportValidationContext(
990 Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge)
991 {
992 dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge);
993 }
994
995 void dumpGraphIfAppropriate()
996 {
997 if (m_graphDumpMode == DontDumpGraph)
998 return;
999 dataLog("\n");
1000 if (!m_graphDumpBeforePhase.isNull()) {
1001 dataLog("Before phase:\n");
1002 dataLog(m_graphDumpBeforePhase);
1003 }
1004 dataLog("At time of failure:\n");
1005 m_graph.dump();
1006 }
1007};
1008
1009} // End anonymous namespace.
1010
1011void validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase)
1012{
1013 Validate validationObject(graph, graphDumpMode, graphDumpBeforePhase);
1014 validationObject.validate();
1015}
1016
1017} } // namespace JSC::DFG
1018
1019#endif // ENABLE(DFG_JIT)
1020
1021