V8 Project
verifier.cc
Go to the documentation of this file.
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <deque>
8 #include <queue>
9 
13 #include "src/compiler/graph-inl.h"
14 #include "src/compiler/graph.h"
15 #include "src/compiler/node.h"
18 #include "src/compiler/opcodes.h"
19 #include "src/compiler/operator.h"
20 #include "src/compiler/schedule.h"
21 #include "src/data-flow.h"
22 
23 namespace v8 {
24 namespace internal {
25 namespace compiler {
26 
27 
28 static bool IsDefUseChainLinkPresent(Node* def, Node* use) {
29  Node::Uses uses = def->uses();
30  for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
31  if (*it == use) return true;
32  }
33  return false;
34 }
35 
36 
37 static bool IsUseDefChainLinkPresent(Node* def, Node* use) {
38  Node::Inputs inputs = use->inputs();
39  for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) {
40  if (*it == def) return true;
41  }
42  return false;
43 }
44 
45 
47  public:
48  explicit Visitor(Zone* zone)
49  : reached_from_start(NodeSet::key_compare(),
50  NodeSet::allocator_type(zone)),
51  reached_from_end(NodeSet::key_compare(),
52  NodeSet::allocator_type(zone)) {}
53 
54  // Fulfills the PreNodeCallback interface.
55  GenericGraphVisit::Control Pre(Node* node);
56 
57  bool from_start;
60 };
61 
62 
64  int value_count = OperatorProperties::GetValueInputCount(node->op());
65  int context_count = OperatorProperties::GetContextInputCount(node->op());
66  int frame_state_count =
68  int effect_count = OperatorProperties::GetEffectInputCount(node->op());
69  int control_count = OperatorProperties::GetControlInputCount(node->op());
70 
71  // Verify number of inputs matches up.
72  int input_count = value_count + context_count + frame_state_count +
73  effect_count + control_count;
74  CHECK_EQ(input_count, node->InputCount());
75 
76  // Verify that frame state has been inserted for the nodes that need it.
78  Node* frame_state = NodeProperties::GetFrameStateInput(node);
79  CHECK(frame_state->opcode() == IrOpcode::kFrameState ||
80  // kFrameState uses undefined as a sentinel.
81  (node->opcode() == IrOpcode::kFrameState &&
82  frame_state->opcode() == IrOpcode::kHeapConstant));
83  CHECK(IsDefUseChainLinkPresent(frame_state, node));
84  CHECK(IsUseDefChainLinkPresent(frame_state, node));
85  }
86 
87  // Verify all value inputs actually produce a value.
88  for (int i = 0; i < value_count; ++i) {
89  Node* value = NodeProperties::GetValueInput(node, i);
91  CHECK(IsDefUseChainLinkPresent(value, node));
92  CHECK(IsUseDefChainLinkPresent(value, node));
93  }
94 
95  // Verify all context inputs are value nodes.
96  for (int i = 0; i < context_count; ++i) {
97  Node* context = NodeProperties::GetContextInput(node);
99  CHECK(IsDefUseChainLinkPresent(context, node));
100  CHECK(IsUseDefChainLinkPresent(context, node));
101  }
102 
103  // Verify all effect inputs actually have an effect.
104  for (int i = 0; i < effect_count; ++i) {
105  Node* effect = NodeProperties::GetEffectInput(node);
107  CHECK(IsDefUseChainLinkPresent(effect, node));
108  CHECK(IsUseDefChainLinkPresent(effect, node));
109  }
110 
111  // Verify all control inputs are control nodes.
112  for (int i = 0; i < control_count; ++i) {
113  Node* control = NodeProperties::GetControlInput(node, i);
115  CHECK(IsDefUseChainLinkPresent(control, node));
116  CHECK(IsUseDefChainLinkPresent(control, node));
117  }
118 
119  // Verify all successors are projections if multiple value outputs exist.
120  if (OperatorProperties::GetValueOutputCount(node->op()) > 1) {
121  Node::Uses uses = node->uses();
122  for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
123  CHECK(!NodeProperties::IsValueEdge(it.edge()) ||
124  (*it)->opcode() == IrOpcode::kProjection ||
125  (*it)->opcode() == IrOpcode::kParameter);
126  }
127  }
128 
129  switch (node->opcode()) {
130  case IrOpcode::kStart:
131  // Start has no inputs.
132  CHECK_EQ(0, input_count);
133  break;
134  case IrOpcode::kEnd:
135  // End has no outputs.
139  break;
140  case IrOpcode::kDead:
141  // Dead is never connected to the graph.
142  UNREACHABLE();
143  case IrOpcode::kBranch: {
144  // Branch uses are IfTrue and IfFalse.
145  Node::Uses uses = node->uses();
146  bool got_true = false, got_false = false;
147  for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
148  CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) ||
149  ((*it)->opcode() == IrOpcode::kIfFalse && !got_false));
150  if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true;
151  if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true;
152  }
153  // TODO(rossberg): Currently fails for various tests.
154  // CHECK(got_true && got_false);
155  break;
156  }
157  case IrOpcode::kIfTrue:
158  case IrOpcode::kIfFalse:
159  CHECK_EQ(IrOpcode::kBranch,
160  NodeProperties::GetControlInput(node, 0)->opcode());
161  break;
162  case IrOpcode::kLoop:
163  case IrOpcode::kMerge:
164  break;
165  case IrOpcode::kReturn:
166  // TODO(rossberg): check successor is End
167  break;
168  case IrOpcode::kThrow:
169  // TODO(rossberg): what are the constraints on these?
170  break;
171  case IrOpcode::kParameter: {
172  // Parameters have the start node as inputs.
173  CHECK_EQ(1, input_count);
174  CHECK_EQ(IrOpcode::kStart,
175  NodeProperties::GetValueInput(node, 0)->opcode());
176  // Parameter has an input that produces enough values.
177  int index = OpParameter<int>(node);
178  Node* input = NodeProperties::GetValueInput(node, 0);
179  // Currently, parameter indices start at -1 instead of 0.
180  CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
181  break;
182  }
183  case IrOpcode::kInt32Constant:
184  case IrOpcode::kInt64Constant:
185  case IrOpcode::kFloat64Constant:
186  case IrOpcode::kExternalConstant:
187  case IrOpcode::kNumberConstant:
188  case IrOpcode::kHeapConstant:
189  // Constants have no inputs.
190  CHECK_EQ(0, input_count);
191  break;
192  case IrOpcode::kPhi: {
193  // Phi input count matches parent control node.
194  CHECK_EQ(1, control_count);
195  Node* control = NodeProperties::GetControlInput(node, 0);
196  CHECK_EQ(value_count,
198  break;
199  }
200  case IrOpcode::kEffectPhi: {
201  // EffectPhi input count matches parent control node.
202  CHECK_EQ(1, control_count);
203  Node* control = NodeProperties::GetControlInput(node, 0);
204  CHECK_EQ(effect_count,
206  break;
207  }
208  case IrOpcode::kFrameState:
209  // TODO(jarin): what are the constraints on these?
210  break;
211  case IrOpcode::kCall:
212  // TODO(rossberg): what are the constraints on these?
213  break;
214  case IrOpcode::kProjection: {
215  // Projection has an input that produces enough values.
216  size_t index = OpParameter<size_t>(node);
217  Node* input = NodeProperties::GetValueInput(node, 0);
219  static_cast<int>(index));
220  break;
221  }
222  default:
223  // TODO(rossberg): Check other node kinds.
224  break;
225  }
226 
227  if (from_start) {
228  reached_from_start.insert(node);
229  } else {
230  reached_from_end.insert(node);
231  }
232 
234 }
235 
236 
237 void Verifier::Run(Graph* graph) {
238  Visitor visitor(graph->zone());
239 
240  CHECK_NE(NULL, graph->start());
241  visitor.from_start = true;
242  graph->VisitNodeUsesFromStart(&visitor);
243  CHECK_NE(NULL, graph->end());
244  visitor.from_start = false;
245  graph->VisitNodeInputsFromEnd(&visitor);
246 
247  // All control nodes reachable from end are reachable from start.
248  for (NodeSet::iterator it = visitor.reached_from_end.begin();
249  it != visitor.reached_from_end.end(); ++it) {
251  visitor.reached_from_start.count(*it));
252  }
253 }
254 
255 
256 static bool HasDominatingDef(Schedule* schedule, Node* node,
257  BasicBlock* container, BasicBlock* use_block,
258  int use_pos) {
259  BasicBlock* block = use_block;
260  while (true) {
261  while (use_pos >= 0) {
262  if (block->nodes_[use_pos] == node) return true;
263  use_pos--;
264  }
265  block = block->dominator_;
266  if (block == NULL) break;
267  use_pos = static_cast<int>(block->nodes_.size()) - 1;
268  if (node == block->control_input_) return true;
269  }
270  return false;
271 }
272 
273 
274 static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
275  Node* node, int use_pos) {
276  for (int j = OperatorProperties::GetValueInputCount(node->op()) - 1; j >= 0;
277  j--) {
278  BasicBlock* use_block = block;
279  if (node->opcode() == IrOpcode::kPhi) {
280  use_block = use_block->PredecessorAt(j);
281  use_pos = static_cast<int>(use_block->nodes_.size()) - 1;
282  }
283  Node* input = node->InputAt(j);
284  if (!HasDominatingDef(schedule, node->InputAt(j), block, use_block,
285  use_pos)) {
286  V8_Fatal(__FILE__, __LINE__,
287  "Node #%d:%s in B%d is not dominated by input@%d #%d:%s",
288  node->id(), node->op()->mnemonic(), block->id(), j, input->id(),
289  input->op()->mnemonic());
290  }
291  }
292 }
293 
294 
296  const int count = schedule->BasicBlockCount();
297  Zone tmp_zone(schedule->zone()->isolate());
298  Zone* zone = &tmp_zone;
299  BasicBlock* start = schedule->start();
300  BasicBlockVector* rpo_order = schedule->rpo_order();
301 
302  // Verify the RPO order contains only blocks from this schedule.
303  CHECK_GE(count, static_cast<int>(rpo_order->size()));
304  for (BasicBlockVector::iterator b = rpo_order->begin(); b != rpo_order->end();
305  ++b) {
306  CHECK_EQ((*b), schedule->GetBlockById((*b)->id()));
307  }
308 
309  // Verify RPO numbers of blocks.
310  CHECK_EQ(start, rpo_order->at(0)); // Start should be first.
311  for (size_t b = 0; b < rpo_order->size(); b++) {
312  BasicBlock* block = rpo_order->at(b);
313  CHECK_EQ(static_cast<int>(b), block->rpo_number_);
314  BasicBlock* dom = block->dominator_;
315  if (b == 0) {
316  // All blocks except start should have a dominator.
317  CHECK_EQ(NULL, dom);
318  } else {
319  // Check that the immediate dominator appears somewhere before the block.
320  CHECK_NE(NULL, dom);
321  CHECK_LT(dom->rpo_number_, block->rpo_number_);
322  }
323  }
324 
325  // Verify that all blocks reachable from start are in the RPO.
326  BoolVector marked(count, false, zone);
327  {
328  ZoneQueue<BasicBlock*> queue(zone);
329  queue.push(start);
330  marked[start->id()] = true;
331  while (!queue.empty()) {
332  BasicBlock* block = queue.front();
333  queue.pop();
334  for (int s = 0; s < block->SuccessorCount(); s++) {
335  BasicBlock* succ = block->SuccessorAt(s);
336  if (!marked[succ->id()]) {
337  marked[succ->id()] = true;
338  queue.push(succ);
339  }
340  }
341  }
342  }
343  // Verify marked blocks are in the RPO.
344  for (int i = 0; i < count; i++) {
345  BasicBlock* block = schedule->GetBlockById(i);
346  if (marked[i]) {
347  CHECK_GE(block->rpo_number_, 0);
348  CHECK_EQ(block, rpo_order->at(block->rpo_number_));
349  }
350  }
351  // Verify RPO blocks are marked.
352  for (size_t b = 0; b < rpo_order->size(); b++) {
353  CHECK(marked[rpo_order->at(b)->id()]);
354  }
355 
356  {
357  // Verify the dominance relation.
358  ZoneList<BitVector*> dominators(count, zone);
359  dominators.Initialize(count, zone);
360  dominators.AddBlock(NULL, count, zone);
361 
362  // Compute a set of all the nodes that dominate a given node by using
363  // a forward fixpoint. O(n^2).
364  ZoneQueue<BasicBlock*> queue(zone);
365  queue.push(start);
366  dominators[start->id()] = new (zone) BitVector(count, zone);
367  while (!queue.empty()) {
368  BasicBlock* block = queue.front();
369  queue.pop();
370  BitVector* block_doms = dominators[block->id()];
371  BasicBlock* idom = block->dominator_;
372  if (idom != NULL && !block_doms->Contains(idom->id())) {
373  V8_Fatal(__FILE__, __LINE__, "Block B%d is not dominated by B%d",
374  block->id(), idom->id());
375  }
376  for (int s = 0; s < block->SuccessorCount(); s++) {
377  BasicBlock* succ = block->SuccessorAt(s);
378  BitVector* succ_doms = dominators[succ->id()];
379 
380  if (succ_doms == NULL) {
381  // First time visiting the node. S.doms = B U B.doms
382  succ_doms = new (zone) BitVector(count, zone);
383  succ_doms->CopyFrom(*block_doms);
384  succ_doms->Add(block->id());
385  dominators[succ->id()] = succ_doms;
386  queue.push(succ);
387  } else {
388  // Nth time visiting the successor. S.doms = S.doms ^ (B U B.doms)
389  bool had = succ_doms->Contains(block->id());
390  if (had) succ_doms->Remove(block->id());
391  if (succ_doms->IntersectIsChanged(*block_doms)) queue.push(succ);
392  if (had) succ_doms->Add(block->id());
393  }
394  }
395  }
396 
397  // Verify the immediateness of dominators.
398  for (BasicBlockVector::iterator b = rpo_order->begin();
399  b != rpo_order->end(); ++b) {
400  BasicBlock* block = *b;
401  BasicBlock* idom = block->dominator_;
402  if (idom == NULL) continue;
403  BitVector* block_doms = dominators[block->id()];
404 
405  for (BitVector::Iterator it(block_doms); !it.Done(); it.Advance()) {
406  BasicBlock* dom = schedule->GetBlockById(it.Current());
407  if (dom != idom && !dominators[idom->id()]->Contains(dom->id())) {
408  V8_Fatal(__FILE__, __LINE__,
409  "Block B%d is not immediately dominated by B%d", block->id(),
410  idom->id());
411  }
412  }
413  }
414  }
415 
416  // Verify phis are placed in the block of their control input.
417  for (BasicBlockVector::iterator b = rpo_order->begin(); b != rpo_order->end();
418  ++b) {
419  for (BasicBlock::const_iterator i = (*b)->begin(); i != (*b)->end(); ++i) {
420  Node* phi = *i;
421  if (phi->opcode() != IrOpcode::kPhi) continue;
422  // TODO(titzer): Nasty special case. Phis from RawMachineAssembler
423  // schedules don't have control inputs.
424  if (phi->InputCount() >
426  Node* control = NodeProperties::GetControlInput(phi);
427  CHECK(control->opcode() == IrOpcode::kMerge ||
428  control->opcode() == IrOpcode::kLoop);
429  CHECK_EQ((*b), schedule->block(control));
430  }
431  }
432  }
433 
434  // Verify that all uses are dominated by their definitions.
435  for (BasicBlockVector::iterator b = rpo_order->begin(); b != rpo_order->end();
436  ++b) {
437  BasicBlock* block = *b;
438 
439  // Check inputs to control for this block.
440  Node* control = block->control_input_;
441  if (control != NULL) {
442  CHECK_EQ(block, schedule->block(control));
443  CheckInputsDominate(schedule, block, control,
444  static_cast<int>(block->nodes_.size()) - 1);
445  }
446  // Check inputs for all nodes in the block.
447  for (size_t i = 0; i < block->nodes_.size(); i++) {
448  Node* node = block->nodes_[i];
449  CheckInputsDominate(schedule, block, node, static_cast<int>(i) - 1);
450  }
451  }
452 }
453 }
454 }
455 } // namespace v8::internal::compiler
bool IntersectIsChanged(const BitVector &other)
Definition: data-flow.h:140
void CopyFrom(const BitVector &other)
Definition: data-flow.h:89
bool Contains(int i) const
Definition: data-flow.h:99
bool Contains(const T &elm) const
Definition: list-inl.h:174
Vector< T > AddBlock(T value, int count, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:77
Isolate * isolate() const
Definition: zone.h:68
void VisitNodeUsesFromStart(Visitor *visitor)
Definition: graph-inl.h:24
void VisitNodeInputsFromEnd(Visitor *visitor)
Definition: graph-inl.h:30
static Node * GetContextInput(Node *node)
static Node * GetValueInput(Node *node, int index)
static Node * GetFrameStateInput(Node *node)
static bool IsValueEdge(Node::Edge edge)
static Node * GetEffectInput(Node *node, int index=0)
static Node * GetControlInput(Node *node, int index=0)
static int GetEffectInputCount(const Operator *op)
static int GetFrameStateInputCount(const Operator *op)
static int GetContextInputCount(const Operator *op)
static bool HasValueOutput(const Operator *op)
static int GetValueInputCount(const Operator *op)
static bool HasFrameStateInput(const Operator *op)
static bool HasEffectOutput(const Operator *op)
static int GetValueOutputCount(const Operator *op)
static int GetControlInputCount(const Operator *op)
static bool HasControlOutput(const Operator *op)
static void Run(Schedule *schedule)
Definition: verifier.cc:295
BasicBlock * GetBlockById(int block_id)
Definition: schedule.h:184
BasicBlock * block(Node *node) const
Definition: schedule.h:171
BasicBlockVector * rpo_order()
Definition: schedule.h:279
GenericGraphVisit::Control Pre(Node *node)
Definition: verifier.cc:63
static void Run(Graph *graph)
Definition: verifier.cc:237
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to use(in kBytes)") DEFINE_INT(max_stack_trace_source_length
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
void V8_Fatal(const char *file, int line, const char *format,...)
Definition: logging.cc:75
#define UNREACHABLE()
Definition: logging.h:30
#define CHECK_EQ(expected, value)
Definition: logging.h:169
#define CHECK_LT(a, b)
Definition: logging.h:179
#define CHECK(condition)
Definition: logging.h:36
#define CHECK_NE(unexpected, value)
Definition: logging.h:173
#define CHECK_GE(a, b)
Definition: logging.h:178
#define CHECK_GT(a, b)
Definition: logging.h:177
static bool HasDominatingDef(Schedule *schedule, Node *node, BasicBlock *container, BasicBlock *use_block, int use_pos)
Definition: verifier.cc:256
static bool IsUseDefChainLinkPresent(Node *def, Node *use)
Definition: verifier.cc:37
static bool IsDefUseChainLinkPresent(Node *def, Node *use)
Definition: verifier.cc:28
std::set< Node *, std::less< Node * >, zone_allocator< Node * > > NodeSet
Definition: node.h:68
static void CheckInputsDominate(Schedule *schedule, BasicBlock *block, Node *node, int use_pos)
Definition: verifier.cc:274
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20