]>
Commit | Line | Data |
---|---|---|
93a37866 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2012-2015 Apple Inc. All rights reserved. |
93a37866 A |
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" | |
ed1e77d3 | 32 | #include "DFGMayExit.h" |
81345200 | 33 | #include "JSCInlines.h" |
93a37866 A |
34 | #include <wtf/Assertions.h> |
35 | #include <wtf/BitVector.h> | |
36 | ||
37 | namespace JSC { namespace DFG { | |
38 | ||
39 | class Validate { | |
40 | public: | |
ed1e77d3 | 41 | Validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase) |
93a37866 A |
42 | : m_graph(graph) |
43 | , m_graphDumpMode(graphDumpMode) | |
ed1e77d3 | 44 | , m_graphDumpBeforePhase(graphDumpBeforePhase) |
93a37866 A |
45 | { |
46 | } | |
47 | ||
48 | #define VALIDATE(context, assertion) do { \ | |
49 | if (!(assertion)) { \ | |
81345200 | 50 | startCrashing(); \ |
93a37866 A |
51 | dataLogF("\n\n\nAt "); \ |
52 | reportValidationContext context; \ | |
ed1e77d3 | 53 | dataLogF(": validation failed: %s (%s:%d).\n", #assertion, __FILE__, __LINE__); \ |
93a37866 A |
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) { \ | |
81345200 | 62 | startCrashing(); \ |
93a37866 A |
63 | dataLogF("\n\n\nAt "); \ |
64 | reportValidationContext context; \ | |
ed1e77d3 | 65 | dataLogF(": validation failed: (%s = ", #left); \ |
93a37866 A |
66 | dataLog(left); \ |
67 | dataLogF(") == (%s = ", #right); \ | |
68 | dataLog(right); \ | |
ed1e77d3 | 69 | dataLogF(") (%s:%d).\n", __FILE__, __LINE__); \ |
93a37866 A |
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)) | |
ed1e77d3 | 77 | |
93a37866 A |
78 | void validate() |
79 | { | |
80 | // NB. This code is not written for performance, since it is not intended to run | |
81 | // in release builds. | |
81345200 | 82 | |
93a37866 | 83 | // Validate that all local variables at the head of the root block are dead. |
81345200 | 84 | BasicBlock* root = m_graph.block(0); |
93a37866 | 85 | for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i) |
81345200 | 86 | V_EQUAL((virtualRegisterForLocal(i), root), static_cast<Node*>(0), root->variablesAtHead.local(i)); |
93a37866 A |
87 | |
88 | // Validate ref counts and uses. | |
81345200 A |
89 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { |
90 | BasicBlock* block = m_graph.block(blockIndex); | |
91 | if (!block) | |
93a37866 | 92 | continue; |
81345200 | 93 | VALIDATE((block), block->isReachable); |
93a37866 | 94 | for (size_t i = 0; i < block->numNodes(); ++i) |
81345200 | 95 | m_myRefCounts.add(block->node(i), 0); |
93a37866 | 96 | } |
81345200 A |
97 | for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) { |
98 | BasicBlock* block = m_graph.block(blockIndex); | |
99 | if (!block) | |
93a37866 A |
100 | continue; |
101 | for (size_t i = 0; i < block->numNodes(); ++i) { | |
102 | Node* node = block->node(i); | |
81345200 | 103 | m_acceptableNodes.add(node); |
93a37866 A |
104 | if (!node->shouldGenerate()) |
105 | continue; | |
81345200 A |
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 | } | |
93a37866 A |
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 | ||
81345200 | 120 | m_myRefCounts.find(edge.node())->value++; |
ed1e77d3 A |
121 | |
122 | validateEdgeWithDoubleResultIfNecessary(node, edge); | |
81345200 A |
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 | } | |
93a37866 A |
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: | |
81345200 | 135 | VALIDATE((node, edge), edge->hasVariableAccessData(m_graph)); |
93a37866 A |
136 | VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); |
137 | break; | |
138 | case PhantomLocal: | |
81345200 | 139 | VALIDATE((node, edge), edge->hasVariableAccessData(m_graph)); |
93a37866 A |
140 | VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); |
141 | VALIDATE((node, edge), edge->op() != SetLocal); | |
142 | break; | |
143 | case Phi: | |
81345200 | 144 | VALIDATE((node, edge), edge->hasVariableAccessData(m_graph)); |
93a37866 A |
145 | if (m_graph.m_unificationState == LocallyUnified) |
146 | break; | |
147 | VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); | |
148 | break; | |
93a37866 A |
149 | default: |
150 | VALIDATE((node, edge), edge->hasResult()); | |
151 | break; | |
152 | } | |
153 | } | |
154 | } | |
155 | } | |
81345200 A |
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()); | |
81345200 A |
165 | } |
166 | ||
ed1e77d3 A |
167 | bool foundTerminal = false; |
168 | for (size_t i = 0 ; i < block->size(); ++i) { | |
81345200 | 169 | Node* node = block->at(i); |
ed1e77d3 A |
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 | } | |
81345200 | 183 | } |
ed1e77d3 | 184 | VALIDATE((block), foundTerminal); |
81345200 A |
185 | |
186 | for (size_t i = 0; i < block->size(); ++i) { | |
187 | Node* node = block->at(i); | |
188 | ||
ed1e77d3 A |
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 | ||
81345200 A |
202 | switch (node->op()) { |
203 | case Identity: | |
204 | VALIDATE((node), canonicalResultRepresentation(node->result()) == canonicalResultRepresentation(node->child1()->result())); | |
205 | break; | |
ed1e77d3 A |
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; | |
81345200 A |
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; | |
ed1e77d3 | 280 | CString m_graphDumpBeforePhase; |
81345200 A |
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) | |
93a37866 A |
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); | |
93a37866 A |
300 | for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { |
301 | Edge edge = m_graph.child(node, j); | |
302 | if (!edge) | |
303 | continue; | |
81345200 | 304 | VALIDATE((node, edge), m_acceptableNodes.contains(edge.node())); |
93a37866 A |
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 | |
81345200 | 327 | || edge->op() == Phi); |
93a37866 A |
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 | |
93a37866 A |
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; | |
81345200 A |
345 | for (unsigned k = 0; k < block->predecessors.size(); ++k) { |
346 | BasicBlock* prevBlock = block->predecessors[k]; | |
347 | VALIDATE((block->predecessors[k]), prevBlock); | |
93a37866 A |
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. | |
81345200 | 351 | VALIDATE((local, block, block->predecessors[k]), prevNode); |
93a37866 A |
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()) { | |
81345200 | 362 | VALIDATE((local, block->predecessors[k], prevNode), |
93a37866 A |
363 | prevNode->shouldGenerate()); |
364 | } | |
365 | VALIDATE( | |
81345200 | 366 | (local, block->predecessors[k], prevNode), |
93a37866 | 367 | prevNode->op() == SetLocal |
93a37866 A |
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. | |
81345200 | 375 | VALIDATE((local, block->predecessors[k], prevNode), !prevBlock->isInBlock(edge.node())); |
93a37866 A |
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) { | |
81345200 | 390 | VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData(m_graph)); |
93a37866 | 391 | if (m_graph.m_form == ThreadedCPS) |
81345200 | 392 | VALIDATE((virtualRegisterForArgument(i), block), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData(m_graph)); |
93a37866 A |
393 | |
394 | getLocalPositions.argument(i) = notSet; | |
395 | setLocalPositions.argument(i) = notSet; | |
396 | } | |
397 | for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { | |
81345200 | 398 | VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData(m_graph)); |
93a37866 | 399 | if (m_graph.m_form == ThreadedCPS) |
81345200 | 400 | VALIDATE((virtualRegisterForLocal(i), block), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData(m_graph)); |
93a37866 A |
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); | |
ed1e77d3 | 410 | VALIDATE((node), node->origin.forExit.isSet()); |
93a37866 A |
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; | |
93a37866 A |
421 | default: |
422 | VALIDATE((node, edge), !phisInThisBlock.contains(edge.node())); | |
423 | break; | |
424 | } | |
425 | } | |
426 | ||
ed1e77d3 A |
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 | ||
93a37866 A |
451 | if (!node->shouldGenerate()) |
452 | continue; | |
453 | switch (node->op()) { | |
454 | case GetLocal: | |
93a37866 A |
455 | // Ignore GetLocal's that we know to be dead, but that the graph |
456 | // doesn't yet know to be dead. | |
81345200 | 457 | if (!m_myRefCounts.get(node)) |
93a37866 | 458 | break; |
ed1e77d3 | 459 | if (m_graph.m_form == ThreadedCPS) { |
81345200 | 460 | VALIDATE((node, block), getLocalPositions.operand(node->local()) == notSet); |
ed1e77d3 A |
461 | VALIDATE((node, block), !!node->child1()); |
462 | } | |
93a37866 A |
463 | getLocalPositions.operand(node->local()) = i; |
464 | break; | |
465 | case SetLocal: | |
93a37866 A |
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; | |
ed1e77d3 A |
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; | |
93a37866 A |
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( | |
81345200 | 488 | block, getLocalPositions, setLocalPositions, virtualRegisterForArgument(i)); |
93a37866 A |
489 | } |
490 | for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { | |
491 | checkOperand( | |
81345200 | 492 | block, getLocalPositions, setLocalPositions, virtualRegisterForLocal(i)); |
93a37866 A |
493 | } |
494 | } | |
495 | } | |
496 | ||
81345200 A |
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 | ||
ed1e77d3 A |
507 | VALIDATE((block), block->phis.isEmpty()); |
508 | ||
81345200 | 509 | unsigned nodeIndex = 0; |
ed1e77d3 | 510 | for (; nodeIndex < block->size() && !block->at(nodeIndex)->origin.forExit.isSet(); nodeIndex++) { } |
81345200 A |
511 | |
512 | VALIDATE((block), nodeIndex < block->size()); | |
513 | ||
514 | for (; nodeIndex < block->size(); nodeIndex++) | |
ed1e77d3 | 515 | VALIDATE((block->at(nodeIndex)), block->at(nodeIndex)->origin.forExit.isSet()); |
81345200 A |
516 | |
517 | for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { | |
518 | Node* node = block->at(nodeIndex); | |
519 | switch (node->op()) { | |
520 | case Phi: | |
ed1e77d3 A |
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"); | |
81345200 A |
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 | } | |
ed1e77d3 A |
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 | return; | |
548 | ||
549 | VALIDATE((node, edge), edge.useKind() == DoubleRepUse || edge.useKind() == DoubleRepRealUse || edge.useKind() == DoubleRepMachineIntUse); | |
550 | } | |
551 | ||
93a37866 | 552 | void checkOperand( |
81345200 A |
553 | BasicBlock* block, Operands<size_t>& getLocalPositions, |
554 | Operands<size_t>& setLocalPositions, VirtualRegister operand) | |
93a37866 A |
555 | { |
556 | if (getLocalPositions.operand(operand) == notSet) | |
557 | return; | |
558 | if (setLocalPositions.operand(operand) == notSet) | |
559 | return; | |
560 | ||
93a37866 A |
561 | VALIDATE( |
562 | (block->at(getLocalPositions.operand(operand)), | |
563 | block->at(setLocalPositions.operand(operand)), | |
81345200 | 564 | block), |
93a37866 A |
565 | getLocalPositions.operand(operand) < setLocalPositions.operand(operand)); |
566 | } | |
567 | ||
568 | void reportValidationContext(Node* node) | |
569 | { | |
570 | dataLogF("@%u", node->index()); | |
571 | } | |
572 | ||
81345200 | 573 | void reportValidationContext(BasicBlock* block) |
93a37866 | 574 | { |
81345200 | 575 | dataLog("Block ", *block); |
93a37866 A |
576 | } |
577 | ||
578 | void reportValidationContext(Node* node, Edge edge) | |
579 | { | |
580 | dataLog(node, " -> ", edge); | |
581 | } | |
582 | ||
81345200 | 583 | void reportValidationContext(VirtualRegister local, BasicBlock* block) |
93a37866 | 584 | { |
81345200 | 585 | if (!block) { |
ed1e77d3 | 586 | dataLog(local, " in null Block "); |
81345200 A |
587 | return; |
588 | } | |
589 | ||
ed1e77d3 | 590 | dataLog(local, " in Block ", *block); |
93a37866 A |
591 | } |
592 | ||
593 | void reportValidationContext( | |
81345200 | 594 | VirtualRegister local, BasicBlock* sourceBlock, BasicBlock* destinationBlock) |
93a37866 | 595 | { |
ed1e77d3 | 596 | dataLog(local, " in Block ", *sourceBlock, " -> ", *destinationBlock); |
93a37866 A |
597 | } |
598 | ||
599 | void reportValidationContext( | |
81345200 | 600 | VirtualRegister local, BasicBlock* sourceBlock, Node* prevNode) |
93a37866 | 601 | { |
ed1e77d3 | 602 | dataLog(prevNode, " for ", local, " in Block ", *sourceBlock); |
93a37866 A |
603 | } |
604 | ||
81345200 | 605 | void reportValidationContext(Node* node, BasicBlock* block) |
93a37866 | 606 | { |
81345200 | 607 | dataLog(node, " in Block ", *block); |
93a37866 A |
608 | } |
609 | ||
81345200 | 610 | void reportValidationContext(Node* node, Node* node2, BasicBlock* block) |
93a37866 | 611 | { |
81345200 | 612 | dataLog(node, " and ", node2, " in Block ", *block); |
93a37866 A |
613 | } |
614 | ||
615 | void reportValidationContext( | |
81345200 | 616 | Node* node, BasicBlock* block, Node* expectedNode, Edge incomingEdge) |
93a37866 | 617 | { |
81345200 | 618 | dataLog(node, " in Block ", *block, ", searching for ", expectedNode, " from ", incomingEdge); |
93a37866 A |
619 | } |
620 | ||
621 | void dumpGraphIfAppropriate() | |
622 | { | |
623 | if (m_graphDumpMode == DontDumpGraph) | |
624 | return; | |
ed1e77d3 A |
625 | dataLog("\n"); |
626 | if (!m_graphDumpBeforePhase.isNull()) { | |
627 | dataLog("Before phase:\n"); | |
628 | dataLog(m_graphDumpBeforePhase); | |
629 | } | |
93a37866 A |
630 | dataLog("At time of failure:\n"); |
631 | m_graph.dump(); | |
632 | } | |
633 | }; | |
634 | ||
ed1e77d3 | 635 | void validate(Graph& graph, GraphDumpMode graphDumpMode, CString graphDumpBeforePhase) |
93a37866 | 636 | { |
ed1e77d3 | 637 | Validate validationObject(graph, graphDumpMode, graphDumpBeforePhase); |
93a37866 A |
638 | validationObject.validate(); |
639 | } | |
640 | ||
641 | } } // namespace JSC::DFG | |
642 | ||
643 | #endif // ENABLE(DFG_JIT) | |
644 |