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 ArithAdd:
261 case ArithSub:
262 case ArithMul:
263 case ArithIMul:
264 case ArithDiv:
265 case ArithMod:
266 case ArithMin:
267 case ArithMax:
268 case ArithPow:
269 case CompareLess:
270 case CompareLessEq:
271 case CompareGreater:
272 case CompareGreaterEq:
273 case CompareBelow:
274 case CompareBelowEq:
275 case CompareEq:
276 case CompareStrictEq:
277 case SameValue:
278 case StrCat:
279 VALIDATE((node), !!node->child1());
280 VALIDATE((node), !!node->child2());
281 break;
282 case CompareEqPtr:
283 VALIDATE((node), !!node->child1());
284 VALIDATE((node), !!node->cellOperand()->value() && node->cellOperand()->value().isCell());
285 break;
286 case CheckStructureOrEmpty:
287 VALIDATE((node), is64Bit());
288 VALIDATE((node), !!node->child1());
289 VALIDATE((node), node->child1().useKind() == CellUse);
290 break;
291 case CheckStructure:
292 case StringFromCharCode:
293 VALIDATE((node), !!node->child1());
294 break;
295 case PutStructure:
296 VALIDATE((node), !node->transition()->previous->dfgShouldWatch());
297 break;
298 case MultiPutByOffset:
299 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) {
300 const PutByIdVariant& variant = node->multiPutByOffsetData().variants[i];
301 if (variant.kind() != PutByIdVariant::Transition)
302 continue;
303 VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch());
304 }
305 break;
306 case MaterializeNewObject:
307 for (RegisteredStructure structure : node->structureSet()) {
308 // This only supports structures that are JSFinalObject or JSArray.
309 VALIDATE(
310 (node),
311 structure->classInfo() == JSFinalObject::info()
312 || structure->classInfo() == JSArray::info());
313
314 // We only support certain indexing shapes.
315 VALIDATE((node), !hasAnyArrayStorage(structure->indexingType()));
316 }
317 break;
318 case DoubleConstant:
319 case Int52Constant:
320 VALIDATE((node), node->isNumberConstant());
321 break;
322 case GetByOffset:
323 case PutByOffset:
324 // FIXME: We should be able to validate that GetByOffset and PutByOffset are
325 // using the same object for storage and base. I think this means finally
326 // splitting these nodes into two node types, one for inline and one for
327 // out-of-line. The out-of-line one will require that the first node is storage,
328 // while the inline one will not take a storage child at all.
329 // https://bugs.webkit.org/show_bug.cgi?id=159602
330 break;
331 case HasOwnProperty: {
332 VALIDATE((node), !!m_graph.m_vm.hasOwnPropertyCache());
333 break;
334 }
335 case GetVectorLength: {
336 Array::Type type = node->arrayMode().type();
337 VALIDATE((node), type == Array::ArrayStorage || type == Array::SlowPutArrayStorage);
338 break;
339 }
340 case CPUIntrinsic: {
341 switch (node->intrinsic()) {
342 case CPUMfenceIntrinsic:
343 case CPURdtscIntrinsic:
344 case CPUCpuidIntrinsic:
345 case CPUPauseIntrinsic:
346 break;
347 default:
348 VALIDATE((node), false);
349 break;
350 }
351 break;
352 }
353 case GetArgumentCountIncludingThis: {
354 if (InlineCallFrame* inlineCallFrame = node->argumentsInlineCallFrame())
355 VALIDATE((node), inlineCallFrame->isVarargs());
356 break;
357 }
358 case NewArray:
359 VALIDATE((node), node->vectorLengthHint() >= node->numChildren());
360 break;
361 case NewArrayBuffer:
362 VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length());
363 break;
364 default:
365 break;
366 }
367 }
368 }
369
370 switch (m_graph.m_form) {
371 case LoadStore:
372 case ThreadedCPS:
373 validateCPS();
374 break;
375
376 case SSA:
377 validateSSA();
378 break;
379 }
380
381 // Validate clobbered states.
382 struct DefLambdaAdaptor {
383 Function<void(PureValue)> pureValue;
384 Function<void(HeapLocation, LazyNode)> locationAndNode;
385
386 void operator()(PureValue value) const
387 {
388 pureValue(value);
389 }
390
391 void operator()(HeapLocation location, LazyNode node) const
392 {
393 locationAndNode(location, node);
394 }
395 };
396 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
397 for (Node* node : *block) {
398 clobberize(m_graph, node,
399 [&] (AbstractHeap) { },
400 [&] (AbstractHeap heap)
401 {
402 // CSE assumes that HEAP TOP is never written.
403 // If this assumption is weakened, you need to update clobbering
404 // in CSE accordingly.
405 if (heap.kind() == Stack)
406 VALIDATE((node), !heap.payload().isTop());
407 },
408 DefLambdaAdaptor {
409 [&] (PureValue) { },
410 [&] (HeapLocation location, LazyNode)
411 {
412 VALIDATE((node), location.heap().kind() != SideState);
413
414 // More specific kinds should be used instead.
415 VALIDATE((node), location.heap().kind() != World);
416 VALIDATE((node), location.heap().kind() != Heap);
417 }
418 });
419 }
420 }
421
422 for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
423 // We expect the predecessor list to be de-duplicated.
424 HashSet<BasicBlock*> predecessors;
425 for (BasicBlock* predecessor : block->predecessors)
426 predecessors.add(predecessor);
427 VALIDATE((block), predecessors.size() == block->predecessors.size());
428 }
429 }
430
431private:
432 Graph& m_graph;
433 GraphDumpMode m_graphDumpMode;
434 CString m_graphDumpBeforePhase;
435
436 HashMap<Node*, unsigned> m_myRefCounts;
437 HashSet<Node*> m_acceptableNodes;
438
439 void validateCPS()
440 {
441 VALIDATE((), !m_graph.m_rootToArguments.isEmpty()); // We should have at least one root.
442 VALIDATE((), m_graph.m_rootToArguments.size() == m_graph.m_roots.size());
443 for (BasicBlock* root : m_graph.m_rootToArguments.keys())
444 VALIDATE((), m_graph.m_roots.contains(root));
445
446 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
447 BasicBlock* block = m_graph.block(blockIndex);
448 if (!block)
449 continue;
450
451 HashSet<Node*> phisInThisBlock;
452 HashSet<Node*> nodesInThisBlock;
453
454 for (size_t i = 0; i < block->numNodes(); ++i) {
455 Node* node = block->node(i);
456 nodesInThisBlock.add(node);
457 if (block->isPhiIndex(i))
458 phisInThisBlock.add(node);
459 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
460 Edge edge = m_graph.child(node, j);
461 if (!edge)
462 continue;
463 VALIDATE((node, edge), m_acceptableNodes.contains(edge.node()));
464 }
465 }
466
467 {
468 HashSet<Node*> seenNodes;
469 for (size_t i = 0; i < block->size(); ++i) {
470 Node* node = block->at(i);
471 m_graph.doToChildren(node, [&] (const Edge& edge) {
472 Node* child = edge.node();
473 VALIDATE((node), block->isInPhis(child) || seenNodes.contains(child));
474 });
475 seenNodes.add(node);
476 }
477 }
478
479 for (size_t i = 0; i < block->phis.size(); ++i) {
480 Node* node = block->phis[i];
481 ASSERT(phisInThisBlock.contains(node));
482 VALIDATE((node), node->op() == Phi);
483 VirtualRegister local = node->local();
484 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
485 // Phi children in LoadStore form are invalid.
486 if (m_graph.m_form == LoadStore && block->isPhiIndex(i))
487 continue;
488
489 Edge edge = m_graph.child(node, j);
490 if (!edge)
491 continue;
492
493 VALIDATE(
494 (node, edge),
495 edge->op() == SetLocal
496 || edge->op() == SetArgument
497 || edge->op() == Flush
498 || edge->op() == Phi);
499
500 if (phisInThisBlock.contains(edge.node()))
501 continue;
502
503 if (nodesInThisBlock.contains(edge.node())) {
504 VALIDATE(
505 (node, edge),
506 edge->op() == SetLocal
507 || edge->op() == SetArgument
508 || edge->op() == Flush);
509
510 continue;
511 }
512
513 // There must exist a predecessor block that has this node index in
514 // its tail variables.
515 bool found = false;
516 for (unsigned k = 0; k < block->predecessors.size(); ++k) {
517 BasicBlock* prevBlock = block->predecessors[k];
518 VALIDATE((block->predecessors[k]), prevBlock);
519 Node* prevNode = prevBlock->variablesAtTail.operand(local);
520 // If we have a Phi that is not referring to *this* block then all predecessors
521 // must have that local available.
522 VALIDATE((local, block, block->predecessors[k]), prevNode);
523 switch (prevNode->op()) {
524 case GetLocal:
525 case Flush:
526 case PhantomLocal:
527 prevNode = prevNode->child1().node();
528 break;
529 default:
530 break;
531 }
532 if (node->shouldGenerate()) {
533 VALIDATE((local, block->predecessors[k], prevNode),
534 prevNode->shouldGenerate());
535 }
536 VALIDATE(
537 (local, block->predecessors[k], prevNode),
538 prevNode->op() == SetLocal
539 || prevNode->op() == SetArgument
540 || prevNode->op() == Phi);
541 if (prevNode == edge.node()) {
542 found = true;
543 break;
544 }
545 // At this point it cannot refer into this block.
546 VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node()));
547 }
548
549 VALIDATE((node, edge), found);
550 }
551 }
552
553 Operands<size_t> getLocalPositions(
554 block->variablesAtHead.numberOfArguments(),
555 block->variablesAtHead.numberOfLocals());
556 Operands<size_t> setLocalPositions(
557 block->variablesAtHead.numberOfArguments(),
558 block->variablesAtHead.numberOfLocals());
559
560 for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
561 VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->accessesStack(m_graph));
562 if (m_graph.m_form == ThreadedCPS)
563 VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->accessesStack(m_graph));
564
565 getLocalPositions.argument(i) = notSet;
566 setLocalPositions.argument(i) = notSet;
567 }
568 for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
569 VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->accessesStack(m_graph));
570 if (m_graph.m_form == ThreadedCPS)
571 VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->accessesStack(m_graph));
572
573 getLocalPositions.local(i) = notSet;
574 setLocalPositions.local(i) = notSet;
575 }
576
577 for (size_t i = 0; i < block->size(); ++i) {
578 Node* node = block->at(i);
579 ASSERT(nodesInThisBlock.contains(node));
580 VALIDATE((node), node->op() != Phi);
581 VALIDATE((node), node->origin.forExit.isSet());
582 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
583 Edge edge = m_graph.child(node, j);
584 if (!edge)
585 continue;
586 VALIDATE((node, edge), nodesInThisBlock.contains(edge.node()));
587 switch (node->op()) {
588 case PhantomLocal:
589 case GetLocal:
590 case Flush:
591 break;
592 default:
593 VALIDATE((node, edge), !phisInThisBlock.contains(edge.node()));
594 break;
595 }
596 }
597
598 switch (node->op()) {
599 case Phi:
600 case Upsilon:
601 case CheckInBounds:
602 case PhantomNewObject:
603 case PhantomNewFunction:
604 case PhantomNewGeneratorFunction:
605 case PhantomNewAsyncFunction:
606 case PhantomNewAsyncGeneratorFunction:
607 case PhantomCreateActivation:
608 case PhantomNewRegexp:
609 case GetMyArgumentByVal:
610 case GetMyArgumentByValOutOfBounds:
611 case PutHint:
612 case CheckStructureImmediate:
613 case MaterializeCreateActivation:
614 case PutStack:
615 case KillStack:
616 case GetStack:
617 case EntrySwitch:
618 case InitializeEntrypointArguments:
619 VALIDATE((node), !"unexpected node type in CPS");
620 break;
621 case MaterializeNewObject: {
622 // CPS only allows array lengths to be constant. This constraint only exists
623 // because we don't have DFG support for anything more and we don't need any
624 // other kind of support for now.
625 ObjectMaterializationData& data = node->objectMaterializationData();
626 for (unsigned i = data.m_properties.size(); i--;) {
627 PromotedLocationDescriptor descriptor = data.m_properties[i];
628 Edge edge = m_graph.varArgChild(node, 1 + i);
629 switch (descriptor.kind()) {
630 case PublicLengthPLoc:
631 case VectorLengthPLoc:
632 VALIDATE((node, edge), edge->isInt32Constant());
633 break;
634 default:
635 break;
636 }
637 }
638
639 // CPS only allows one structure.
640 VALIDATE((node), node->structureSet().size() == 1);
641
642 // CPS disallows int32 and double arrays. Those require weird type checks and
643 // conversions. They are not needed in the DFG right now. We should add support
644 // for these if the DFG ever needs it.
645 for (RegisteredStructure structure : node->structureSet()) {
646 VALIDATE((node), !hasInt32(structure->indexingType()));
647 VALIDATE((node), !hasDouble(structure->indexingType()));
648 }
649 break;
650 }
651 case Phantom:
652 VALIDATE((node), m_graph.m_fixpointState != FixpointNotConverged);
653 break;
654 default:
655 break;
656 }
657
658 if (!node->shouldGenerate())
659 continue;
660 switch (node->op()) {
661 case GetLocal:
662 // Ignore GetLocal's that we know to be dead, but that the graph
663 // doesn't yet know to be dead.
664 if (!m_myRefCounts.get(node))
665 break;
666 if (m_graph.m_form == ThreadedCPS) {
667 VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet);
668 VALIDATE((node, block), !!node->child1());
669 }
670 getLocalPositions.operand(node->local()) = i;
671 break;
672 case SetLocal:
673 // Only record the first SetLocal. There may be multiple SetLocals
674 // because of flushing.
675 if (setLocalPositions.operand(node->local()) != notSet)
676 break;
677 setLocalPositions.operand(node->local()) = i;
678 break;
679 case SetArgument:
680 // This acts like a reset. It's ok to have a second GetLocal for a local in the same
681 // block if we had a SetArgument for that local.
682 getLocalPositions.operand(node->local()) = notSet;
683 setLocalPositions.operand(node->local()) = notSet;
684 break;
685 default:
686 break;
687 }
688 }
689
690 if (m_graph.m_form == LoadStore)
691 continue;
692
693 for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) {
694 checkOperand(
695 block, getLocalPositions, setLocalPositions, virtualRegisterForArgument(i));
696 }
697 for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) {
698 checkOperand(
699 block, getLocalPositions, setLocalPositions, virtualRegisterForLocal(i));
700 }
701 }
702 }
703
704 void validateSSA()
705 {
706 // FIXME: Add more things here.
707 // https://bugs.webkit.org/show_bug.cgi?id=123471
708
709 VALIDATE((), m_graph.m_roots.size() == 1);
710 VALIDATE((), m_graph.m_roots[0] == m_graph.block(0));
711 VALIDATE((), !m_graph.m_argumentFormats.isEmpty()); // We always have at least one entrypoint.
712 VALIDATE((), m_graph.m_rootToArguments.isEmpty()); // This is only used in CPS.
713
714 for (unsigned entrypointIndex : m_graph.m_entrypointIndexToCatchBytecodeOffset.keys())
715 VALIDATE((), entrypointIndex > 0); // By convention, 0 is the entrypoint index for the op_enter entrypoint, which can not be in a catch.
716
717 for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
718 BasicBlock* block = m_graph.block(blockIndex);
719 if (!block)
720 continue;
721
722 VALIDATE((block), block->phis.isEmpty());
723
724 bool didSeeExitOK = false;
725 bool isOSRExited = false;
726
727 for (auto* node : *block) {
728 didSeeExitOK |= node->origin.exitOK;
729 switch (node->op()) {
730 case Phi:
731 // Phi cannot exit, and it would be wrong to hoist anything to the Phi that could
732 // exit.
733 VALIDATE((node), !node->origin.exitOK);
734
735 // It never makes sense to have exitOK anywhere in the block before a Phi. It's only
736 // OK to exit after all Phis are done.
737 VALIDATE((node), !didSeeExitOK);
738 break;
739
740 case GetLocal:
741 case SetLocal:
742 case SetArgument:
743 case Phantom:
744 VALIDATE((node), !"bad node type for SSA");
745 break;
746
747 default:
748 // FIXME: Add more things here.
749 // https://bugs.webkit.org/show_bug.cgi?id=123471
750 break;
751 }
752
753 if (isOSRExited)
754 continue;
755 switch (node->op()) {
756 case PhantomNewObject:
757 case PhantomNewFunction:
758 case PhantomNewGeneratorFunction:
759 case PhantomNewAsyncFunction:
760 case PhantomNewAsyncGeneratorFunction:
761 case PhantomCreateActivation:
762 case PhantomDirectArguments:
763 case PhantomCreateRest:
764 case PhantomClonedArguments:
765 case PhantomNewRegexp:
766 case MovHint:
767 case Upsilon:
768 case ForwardVarargs:
769 case CallForwardVarargs:
770 case TailCallForwardVarargs:
771 case TailCallForwardVarargsInlinedCaller:
772 case ConstructForwardVarargs:
773 case GetMyArgumentByVal:
774 case GetMyArgumentByValOutOfBounds:
775 break;
776
777 case Check:
778 case CheckVarargs:
779 // FIXME: This is probably not correct.
780 break;
781
782 case PutHint:
783 VALIDATE((node), node->child1()->isPhantomAllocation());
784 break;
785
786 case PhantomSpread:
787 VALIDATE((node), m_graph.m_form == SSA);
788 // We currently support PhantomSpread over PhantomCreateRest and PhantomNewArrayBuffer.
789 VALIDATE((node), node->child1()->op() == PhantomCreateRest || node->child1()->op() == PhantomNewArrayBuffer);
790 break;
791
792 case PhantomNewArrayWithSpread: {
793 VALIDATE((node), m_graph.m_form == SSA);
794 BitVector* bitVector = node->bitVector();
795 for (unsigned i = 0; i < node->numChildren(); i++) {
796 Node* child = m_graph.varArgChild(node, i).node();
797 if (bitVector->get(i)) {
798 // We currently support PhantomSpread over PhantomCreateRest and PhantomNewArrayBuffer.
799 VALIDATE((node), child->op() == PhantomSpread);
800 } else
801 VALIDATE((node), !child->isPhantomAllocation());
802 }
803 break;
804 }
805
806 case PhantomNewArrayBuffer:
807 VALIDATE((node), m_graph.m_form == SSA);
808 VALIDATE((node), node->vectorLengthHint() >= node->castOperand<JSImmutableButterfly*>()->length());
809 break;
810
811 case NewArrayWithSpread: {
812 BitVector* bitVector = node->bitVector();
813 for (unsigned i = 0; i < node->numChildren(); i++) {
814 Node* child = m_graph.varArgChild(node, i).node();
815 if (child->isPhantomAllocation()) {
816 VALIDATE((node), bitVector->get(i));
817 VALIDATE((node), m_graph.m_form == SSA);
818 VALIDATE((node), child->op() == PhantomSpread);
819 }
820 }
821 break;
822 }
823
824 case Spread:
825 VALIDATE((node), !node->child1()->isPhantomAllocation() || node->child1()->op() == PhantomCreateRest || node->child1()->op() == PhantomNewArrayBuffer);
826 break;
827
828 case EntrySwitch:
829 VALIDATE((node), node->entrySwitchData()->cases.size() == m_graph.m_numberOfEntrypoints);
830 break;
831
832 case InitializeEntrypointArguments:
833 VALIDATE((node), node->entrypointIndex() < m_graph.m_numberOfEntrypoints);
834 break;
835
836 default:
837 m_graph.doToChildren(
838 node,
839 [&] (const Edge& edge) {
840 VALIDATE((node), !edge->isPhantomAllocation());
841 });
842 break;
843 }
844 isOSRExited |= node->isPseudoTerminal();
845 }
846 }
847 }
848
849 void validateEdgeWithDoubleResultIfNecessary(Node* node, Edge edge)
850 {
851 if (!edge->hasDoubleResult())
852 return;
853
854 if (m_graph.m_planStage < PlanStage::AfterFixup)
855 return;
856
857 VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepAnyIntUse);
858 }
859
860 void checkOperand(
861 BasicBlock* block, Operands<size_t>& getLocalPositions,
862 Operands<size_t>& setLocalPositions, VirtualRegister operand)
863 {
864 if (getLocalPositions.operand(operand) == notSet)
865 return;
866 if (setLocalPositions.operand(operand) == notSet)
867 return;
868
869 VALIDATE(
870 (block->at(getLocalPositions.operand(operand)),
871 block->at(setLocalPositions.operand(operand)),
872 block),
873 getLocalPositions.operand(operand) < setLocalPositions.operand(operand));
874 }
875
876 void reportValidationContext() { }
877
878 void reportValidationContext(Node* node)
879 {
880 dataLogF("@%u", node->index());
881 }
882
883 void reportValidationContext(BasicBlock* block)
884 {
885 dataLog("Block ", *block);
886 }
887
888 void reportValidationContext(Node* node, Edge edge)
889 {
890 dataLog(node, " -> ", edge);
891 }
892
893 void reportValidationContext(VirtualRegister local, BasicBlock* block)
894 {
895 if (!block) {
896 dataLog(local, " in null Block ");
897 return;
898 }
899
900 dataLog(local, " in Block ", *block);
901 }
902
903 void reportValidationContext(
904 VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock)
905 {
906 dataLog(local, " in Block ", *sourceBlock, " -> ", *destinationBlock);
907 }
908
909 void reportValidationContext(
910 VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode)
911 {
912 dataLog(prevNode, " for ", local, " in Block ", *sourceBlock);
913 }
914
915 void reportValidationContext(Node* node, BasicBlock* block)
916 {
917 dataLog(node, " in Block ", *block);
918 }
919
920 void reportValidationContext(Node* node, Node* node2, BasicBlock* block)
921 {
922 dataLog(node, " and ", node2, " in Block ", *block);
923 }
924
925 void reportValidationContext(
926 Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge)
927 {
928 dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge);
929 }
930
931 void dumpGraphIfAppropriate()
932 {
933 if (m_graphDumpMode == DontDumpGraph)
934 return;
935 dataLog("\n");
936 if (!m_graphDumpBeforePhase.isNull()) {
937 dataLog("Before phase:\n");
938 dataLog(m_graphDumpBeforePhase);
939 }
940 dataLog("At time of failure:\n");
941 m_graph.dump();
942 }
943};
944
945} // End anonymous namespace.
946
947void validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase)
948{
949 Validate validationObject(graph, graphDumpMode, graphDumpBeforePhase);
950 validationObject.validate();
951}
952
953} } // namespace JSC::DFG
954
955#endif // ENABLE(DFG_JIT)
956
957