2 * Copyright (C) 2012-2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGValidate.h"
31 #include "CodeBlockWithJITType.h"
32 #include "JSCInlines.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/BitVector.h>
36 namespace JSC
{ namespace DFG
{
40 Validate(Graph
& graph
, GraphDumpMode graphDumpMode
)
42 , m_graphDumpMode(graphDumpMode
)
46 #define VALIDATE(context, assertion) do { \
49 dataLogF("\n\n\nAt "); \
50 reportValidationContext context; \
51 dataLogF(": validation %s (%s:%d) failed.\n", #assertion, __FILE__, __LINE__); \
52 dumpGraphIfAppropriate(); \
53 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
58 #define V_EQUAL(context, left, right) do { \
59 if (left != right) { \
61 dataLogF("\n\n\nAt "); \
62 reportValidationContext context; \
63 dataLogF(": validation (%s = ", #left); \
65 dataLogF(") == (%s = ", #right); \
67 dataLogF(") (%s:%d) failed.\n", __FILE__, __LINE__); \
68 dumpGraphIfAppropriate(); \
69 WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #left " == " #right); \
74 #define notSet (static_cast<size_t>(-1))
78 // NB. This code is not written for performance, since it is not intended to run
81 // Validate that all local variables at the head of the root block are dead.
82 BasicBlock
* root
= m_graph
.block(0);
83 for (unsigned i
= 0; i
< root
->variablesAtHead
.numberOfLocals(); ++i
)
84 V_EQUAL((virtualRegisterForLocal(i
), root
), static_cast<Node
*>(0), root
->variablesAtHead
.local(i
));
86 // Validate ref counts and uses.
87 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
88 BasicBlock
* block
= m_graph
.block(blockIndex
);
91 VALIDATE((block
), block
->isReachable
);
92 for (size_t i
= 0; i
< block
->numNodes(); ++i
)
93 m_myRefCounts
.add(block
->node(i
), 0);
95 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
96 BasicBlock
* block
= m_graph
.block(blockIndex
);
99 for (size_t i
= 0; i
< block
->numNodes(); ++i
) {
100 Node
* node
= block
->node(i
);
101 m_acceptableNodes
.add(node
);
102 if (!node
->shouldGenerate())
104 if (node
->op() == Upsilon
) {
105 VALIDATE((node
), m_graph
.m_form
== SSA
);
106 if (node
->phi()->shouldGenerate())
107 m_myRefCounts
.find(node
)->value
++;
109 for (unsigned j
= 0; j
< m_graph
.numChildren(node
); ++j
) {
110 // Phi children in LoadStore form are invalid.
111 if (m_graph
.m_form
== LoadStore
&& block
->isPhiIndex(i
))
114 Edge edge
= m_graph
.child(node
, j
);
118 m_myRefCounts
.find(edge
.node())->value
++;
120 VALIDATE((node
, edge
), edge
->hasDoubleResult() == (edge
.useKind() == DoubleRepUse
|| edge
.useKind() == DoubleRepRealUse
|| edge
.useKind() == DoubleRepMachineIntUse
));
121 VALIDATE((node
, edge
), edge
->hasInt52Result() == (edge
.useKind() == Int52RepUse
));
123 if (m_graph
.m_form
== SSA
) {
124 // In SSA, all edges must hasResult().
125 VALIDATE((node
, edge
), edge
->hasResult());
129 // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult().
130 switch (node
->op()) {
133 VALIDATE((node
, edge
), edge
->hasVariableAccessData(m_graph
));
134 VALIDATE((node
, edge
), edge
->variableAccessData() == node
->variableAccessData());
137 VALIDATE((node
, edge
), edge
->hasVariableAccessData(m_graph
));
138 VALIDATE((node
, edge
), edge
->variableAccessData() == node
->variableAccessData());
139 VALIDATE((node
, edge
), edge
->op() != SetLocal
);
142 VALIDATE((node
, edge
), edge
->hasVariableAccessData(m_graph
));
143 if (m_graph
.m_unificationState
== LocallyUnified
)
145 VALIDATE((node
, edge
), edge
->variableAccessData() == node
->variableAccessData());
148 switch (m_graph
.m_form
) {
151 VALIDATE((node
, edge
), edge
->hasResult());
154 switch (edge
->op()) {
160 VALIDATE((node
, edge
), edge
->hasResult());
165 VALIDATE((node
, edge
), edge
->hasResult());
168 RELEASE_ASSERT_NOT_REACHED();
173 VALIDATE((node
, edge
), edge
->hasResult());
180 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
181 BasicBlock
* block
= m_graph
.block(blockIndex
);
184 for (size_t i
= 0; i
< block
->numNodes(); ++i
) {
185 Node
* node
= block
->node(i
);
186 if (m_graph
.m_refCountState
== ExactRefCount
)
187 V_EQUAL((node
), m_myRefCounts
.get(node
), node
->adjustedRefCount());
189 V_EQUAL((node
), node
->refCount(), 1);
192 for (size_t i
= 0 ; i
< block
->size() - 1; ++i
) {
193 Node
* node
= block
->at(i
);
194 VALIDATE((node
), !node
->isTerminal());
197 for (size_t i
= 0; i
< block
->size(); ++i
) {
198 Node
* node
= block
->at(i
);
200 if (node
->hasStructure())
201 VALIDATE((node
), !!node
->structure());
203 switch (node
->op()) {
205 VALIDATE((node
), canonicalResultRepresentation(node
->result()) == canonicalResultRepresentation(node
->child1()->result()));
213 switch (m_graph
.m_form
) {
227 GraphDumpMode m_graphDumpMode
;
229 HashMap
<Node
*, unsigned> m_myRefCounts
;
230 HashSet
<Node
*> m_acceptableNodes
;
234 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
235 BasicBlock
* block
= m_graph
.block(blockIndex
);
239 HashSet
<Node
*> phisInThisBlock
;
240 HashSet
<Node
*> nodesInThisBlock
;
242 for (size_t i
= 0; i
< block
->numNodes(); ++i
) {
243 Node
* node
= block
->node(i
);
244 nodesInThisBlock
.add(node
);
245 if (block
->isPhiIndex(i
))
246 phisInThisBlock
.add(node
);
247 for (unsigned j
= 0; j
< m_graph
.numChildren(node
); ++j
) {
248 Edge edge
= m_graph
.child(node
, j
);
251 VALIDATE((node
, edge
), m_acceptableNodes
.contains(edge
.node()));
255 for (size_t i
= 0; i
< block
->phis
.size(); ++i
) {
256 Node
* node
= block
->phis
[i
];
257 ASSERT(phisInThisBlock
.contains(node
));
258 VALIDATE((node
), node
->op() == Phi
);
259 VirtualRegister local
= node
->local();
260 for (unsigned j
= 0; j
< m_graph
.numChildren(node
); ++j
) {
261 // Phi children in LoadStore form are invalid.
262 if (m_graph
.m_form
== LoadStore
&& block
->isPhiIndex(i
))
265 Edge edge
= m_graph
.child(node
, j
);
271 edge
->op() == SetLocal
272 || edge
->op() == SetArgument
273 || edge
->op() == Flush
274 || edge
->op() == Phi
);
276 if (phisInThisBlock
.contains(edge
.node()))
279 if (nodesInThisBlock
.contains(edge
.node())) {
282 edge
->op() == SetLocal
283 || edge
->op() == SetArgument
284 || edge
->op() == Flush
);
289 // There must exist a predecessor block that has this node index in
290 // its tail variables.
292 for (unsigned k
= 0; k
< block
->predecessors
.size(); ++k
) {
293 BasicBlock
* prevBlock
= block
->predecessors
[k
];
294 VALIDATE((block
->predecessors
[k
]), prevBlock
);
295 Node
* prevNode
= prevBlock
->variablesAtTail
.operand(local
);
296 // If we have a Phi that is not referring to *this* block then all predecessors
297 // must have that local available.
298 VALIDATE((local
, block
, block
->predecessors
[k
]), prevNode
);
299 switch (prevNode
->op()) {
303 prevNode
= prevNode
->child1().node();
308 if (node
->shouldGenerate()) {
309 VALIDATE((local
, block
->predecessors
[k
], prevNode
),
310 prevNode
->shouldGenerate());
313 (local
, block
->predecessors
[k
], prevNode
),
314 prevNode
->op() == SetLocal
315 || prevNode
->op() == SetArgument
316 || prevNode
->op() == Phi
);
317 if (prevNode
== edge
.node()) {
321 // At this point it cannot refer into this block.
322 VALIDATE((local
, block
->predecessors
[k
], prevNode
), !prevBlock
->isInBlock(edge
.node()));
325 VALIDATE((node
, edge
), found
);
329 Operands
<size_t> getLocalPositions(
330 block
->variablesAtHead
.numberOfArguments(),
331 block
->variablesAtHead
.numberOfLocals());
332 Operands
<size_t> setLocalPositions(
333 block
->variablesAtHead
.numberOfArguments(),
334 block
->variablesAtHead
.numberOfLocals());
336 for (size_t i
= 0; i
< block
->variablesAtHead
.numberOfArguments(); ++i
) {
337 VALIDATE((virtualRegisterForArgument(i
), block
), !block
->variablesAtHead
.argument(i
) || block
->variablesAtHead
.argument(i
)->hasVariableAccessData(m_graph
));
338 if (m_graph
.m_form
== ThreadedCPS
)
339 VALIDATE((virtualRegisterForArgument(i
), block
), !block
->variablesAtTail
.argument(i
) || block
->variablesAtTail
.argument(i
)->hasVariableAccessData(m_graph
));
341 getLocalPositions
.argument(i
) = notSet
;
342 setLocalPositions
.argument(i
) = notSet
;
344 for (size_t i
= 0; i
< block
->variablesAtHead
.numberOfLocals(); ++i
) {
345 VALIDATE((virtualRegisterForLocal(i
), block
), !block
->variablesAtHead
.local(i
) || block
->variablesAtHead
.local(i
)->hasVariableAccessData(m_graph
));
346 if (m_graph
.m_form
== ThreadedCPS
)
347 VALIDATE((virtualRegisterForLocal(i
), block
), !block
->variablesAtTail
.local(i
) || block
->variablesAtTail
.local(i
)->hasVariableAccessData(m_graph
));
349 getLocalPositions
.local(i
) = notSet
;
350 setLocalPositions
.local(i
) = notSet
;
353 for (size_t i
= 0; i
< block
->size(); ++i
) {
354 Node
* node
= block
->at(i
);
355 ASSERT(nodesInThisBlock
.contains(node
));
356 VALIDATE((node
), node
->op() != Phi
);
357 for (unsigned j
= 0; j
< m_graph
.numChildren(node
); ++j
) {
358 Edge edge
= m_graph
.child(node
, j
);
361 VALIDATE((node
, edge
), nodesInThisBlock
.contains(edge
.node()));
362 switch (node
->op()) {
368 if (m_graph
.m_form
== LoadStore
&& !j
)
372 VALIDATE((node
, edge
), !phisInThisBlock
.contains(edge
.node()));
377 if (!node
->shouldGenerate())
379 switch (node
->op()) {
381 if (node
->variableAccessData()->isCaptured())
383 // Ignore GetLocal's that we know to be dead, but that the graph
384 // doesn't yet know to be dead.
385 if (!m_myRefCounts
.get(node
))
387 if (m_graph
.m_form
== ThreadedCPS
)
388 VALIDATE((node
, block
), getLocalPositions
.operand(node
->local()) == notSet
);
389 getLocalPositions
.operand(node
->local()) = i
;
392 if (node
->variableAccessData()->isCaptured())
394 // Only record the first SetLocal. There may be multiple SetLocals
395 // because of flushing.
396 if (setLocalPositions
.operand(node
->local()) != notSet
)
398 setLocalPositions
.operand(node
->local()) = i
;
405 if (m_graph
.m_form
== LoadStore
)
408 for (size_t i
= 0; i
< block
->variablesAtHead
.numberOfArguments(); ++i
) {
410 block
, getLocalPositions
, setLocalPositions
, virtualRegisterForArgument(i
));
412 for (size_t i
= 0; i
< block
->variablesAtHead
.numberOfLocals(); ++i
) {
414 block
, getLocalPositions
, setLocalPositions
, virtualRegisterForLocal(i
));
421 // FIXME: Add more things here.
422 // https://bugs.webkit.org/show_bug.cgi?id=123471
424 for (BlockIndex blockIndex
= 0; blockIndex
< m_graph
.numBlocks(); ++blockIndex
) {
425 BasicBlock
* block
= m_graph
.block(blockIndex
);
429 unsigned nodeIndex
= 0;
430 for (; nodeIndex
< block
->size() && !block
->at(nodeIndex
)->origin
.isSet(); nodeIndex
++) { }
432 VALIDATE((block
), nodeIndex
< block
->size());
434 for (; nodeIndex
< block
->size(); nodeIndex
++)
435 VALIDATE((block
->at(nodeIndex
)), block
->at(nodeIndex
)->origin
.isSet());
437 for (unsigned nodeIndex
= 0; nodeIndex
< block
->size(); ++nodeIndex
) {
438 Node
* node
= block
->at(nodeIndex
);
439 switch (node
->op()) {
441 VALIDATE((node
), !node
->origin
.isSet());
445 // FIXME: Add more things here.
446 // https://bugs.webkit.org/show_bug.cgi?id=123471
454 BasicBlock
* block
, Operands
<size_t>& getLocalPositions
,
455 Operands
<size_t>& setLocalPositions
, VirtualRegister operand
)
457 if (getLocalPositions
.operand(operand
) == notSet
)
459 if (setLocalPositions
.operand(operand
) == notSet
)
463 (block
->at(getLocalPositions
.operand(operand
)),
464 block
->at(setLocalPositions
.operand(operand
)),
466 getLocalPositions
.operand(operand
) < setLocalPositions
.operand(operand
));
469 void reportValidationContext(Node
* node
)
471 dataLogF("@%u", node
->index());
474 void reportValidationContext(BasicBlock
* block
)
476 dataLog("Block ", *block
);
479 void reportValidationContext(Node
* node
, Edge edge
)
481 dataLog(node
, " -> ", edge
);
484 void reportValidationContext(VirtualRegister local
, BasicBlock
* block
)
487 dataLog("r", local
, " in null Block ");
491 dataLog("r", local
, " in Block ", *block
);
494 void reportValidationContext(
495 VirtualRegister local
, BasicBlock
* sourceBlock
, BasicBlock
* destinationBlock
)
497 dataLog("r", local
, " in Block ", *sourceBlock
, " -> ", *destinationBlock
);
500 void reportValidationContext(
501 VirtualRegister local
, BasicBlock
* sourceBlock
, Node
* prevNode
)
503 dataLog(prevNode
, " for r", local
, " in Block ", *sourceBlock
);
506 void reportValidationContext(Node
* node
, BasicBlock
* block
)
508 dataLog(node
, " in Block ", *block
);
511 void reportValidationContext(Node
* node
, Node
* node2
, BasicBlock
* block
)
513 dataLog(node
, " and ", node2
, " in Block ", *block
);
516 void reportValidationContext(
517 Node
* node
, BasicBlock
* block
, Node
* expectedNode
, Edge incomingEdge
)
519 dataLog(node
, " in Block ", *block
, ", searching for ", expectedNode
, " from ", incomingEdge
);
522 void dumpGraphIfAppropriate()
524 if (m_graphDumpMode
== DontDumpGraph
)
526 dataLog("At time of failure:\n");
531 void validate(Graph
& graph
, GraphDumpMode graphDumpMode
)
533 Validate
validationObject(graph
, graphDumpMode
);
534 validationObject
.validate();
537 } } // namespace JSC::DFG
539 #endif // ENABLE(DFG_JIT)