| Index: src/compiler/verifier.cc
|
| diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..64eb72e7d645b2352e02c1d2e858d2817fba1269
|
| --- /dev/null
|
| +++ b/src/compiler/verifier.cc
|
| @@ -0,0 +1,232 @@
|
| +// Copyright 2014 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "src/compiler/verifier.h"
|
| +
|
| +#include "src/compiler/generic-algorithm.h"
|
| +#include "src/compiler/generic-node-inl.h"
|
| +#include "src/compiler/generic-node.h"
|
| +#include "src/compiler/graph-inl.h"
|
| +#include "src/compiler/graph.h"
|
| +#include "src/compiler/node.h"
|
| +#include "src/compiler/node-properties-inl.h"
|
| +#include "src/compiler/node-properties.h"
|
| +#include "src/compiler/opcodes.h"
|
| +#include "src/compiler/operator.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace compiler {
|
| +
|
| +
|
| +static bool IsDefUseChainLinkPresent(Node* def, Node* use) {
|
| + Node::Uses uses = def->uses();
|
| + for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
|
| + if (*it == use) return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| +static bool IsUseDefChainLinkPresent(Node* def, Node* use) {
|
| + Node::Inputs inputs = use->inputs();
|
| + for (Node::Inputs::iterator it = inputs.begin(); it != inputs.end(); ++it) {
|
| + if (*it == def) return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +
|
| +class Verifier::Visitor : public NullNodeVisitor {
|
| + public:
|
| + explicit Visitor(Zone* zone)
|
| + : reached_from_start(NodeSet::key_compare(),
|
| + NodeSet::allocator_type(zone)),
|
| + reached_from_end(NodeSet::key_compare(),
|
| + NodeSet::allocator_type(zone)) {}
|
| +
|
| + // Fulfills the PreNodeCallback interface.
|
| + GenericGraphVisit::Control Pre(Node* node);
|
| +
|
| + bool from_start;
|
| + NodeSet reached_from_start;
|
| + NodeSet reached_from_end;
|
| +};
|
| +
|
| +
|
| +GenericGraphVisit::Control Verifier::Visitor::Pre(Node* node) {
|
| + int value_count = NodeProperties::GetValueInputCount(node);
|
| + int context_count = NodeProperties::GetContextInputCount(node);
|
| + int effect_count = NodeProperties::GetEffectInputCount(node);
|
| + int control_count = NodeProperties::GetControlInputCount(node);
|
| +
|
| + // Verify number of inputs matches up.
|
| + int input_count = value_count + context_count + effect_count + control_count;
|
| + CHECK_EQ(input_count, node->InputCount());
|
| +
|
| + // Verify all value inputs actually produce a value.
|
| + for (int i = 0; i < value_count; ++i) {
|
| + Node* value = NodeProperties::GetValueInput(node, i);
|
| + CHECK(NodeProperties::HasValueOutput(value));
|
| + CHECK(IsDefUseChainLinkPresent(value, node));
|
| + CHECK(IsUseDefChainLinkPresent(value, node));
|
| + }
|
| +
|
| + // Verify all context inputs are value nodes.
|
| + for (int i = 0; i < context_count; ++i) {
|
| + Node* context = NodeProperties::GetContextInput(node);
|
| + CHECK(NodeProperties::HasValueOutput(context));
|
| + CHECK(IsDefUseChainLinkPresent(context, node));
|
| + CHECK(IsUseDefChainLinkPresent(context, node));
|
| + }
|
| +
|
| + // Verify all effect inputs actually have an effect.
|
| + for (int i = 0; i < effect_count; ++i) {
|
| + Node* effect = NodeProperties::GetEffectInput(node);
|
| + CHECK(NodeProperties::HasEffectOutput(effect));
|
| + CHECK(IsDefUseChainLinkPresent(effect, node));
|
| + CHECK(IsUseDefChainLinkPresent(effect, node));
|
| + }
|
| +
|
| + // Verify all control inputs are control nodes.
|
| + for (int i = 0; i < control_count; ++i) {
|
| + Node* control = NodeProperties::GetControlInput(node, i);
|
| + CHECK(NodeProperties::HasControlOutput(control));
|
| + CHECK(IsDefUseChainLinkPresent(control, node));
|
| + CHECK(IsUseDefChainLinkPresent(control, node));
|
| + }
|
| +
|
| + // Verify all successors are projections if multiple value outputs exist.
|
| + if (NodeProperties::GetValueOutputCount(node) > 1) {
|
| + Node::Uses uses = node->uses();
|
| + for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
|
| + CHECK(!NodeProperties::IsValueEdge(it.edge()) ||
|
| + (*it)->opcode() == IrOpcode::kProjection);
|
| + }
|
| + }
|
| +
|
| + switch (node->opcode()) {
|
| + case IrOpcode::kStart:
|
| + // Start has no inputs.
|
| + CHECK_EQ(0, input_count);
|
| + break;
|
| + case IrOpcode::kEnd:
|
| + // End has no outputs.
|
| + CHECK(!NodeProperties::HasValueOutput(node));
|
| + CHECK(!NodeProperties::HasEffectOutput(node));
|
| + CHECK(!NodeProperties::HasControlOutput(node));
|
| + break;
|
| + case IrOpcode::kDead:
|
| + // Dead is never connected to the graph.
|
| + UNREACHABLE();
|
| + case IrOpcode::kBranch: {
|
| + // Branch uses are IfTrue and IfFalse.
|
| + Node::Uses uses = node->uses();
|
| + bool got_true = false, got_false = false;
|
| + for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
|
| + CHECK(((*it)->opcode() == IrOpcode::kIfTrue && !got_true) ||
|
| + ((*it)->opcode() == IrOpcode::kIfFalse && !got_false));
|
| + if ((*it)->opcode() == IrOpcode::kIfTrue) got_true = true;
|
| + if ((*it)->opcode() == IrOpcode::kIfFalse) got_false = true;
|
| + }
|
| + // TODO(rossberg): Currently fails for various tests.
|
| + // CHECK(got_true && got_false);
|
| + break;
|
| + }
|
| + case IrOpcode::kIfTrue:
|
| + case IrOpcode::kIfFalse:
|
| + CHECK_EQ(IrOpcode::kBranch,
|
| + NodeProperties::GetControlInput(node, 0)->opcode());
|
| + break;
|
| + case IrOpcode::kLoop:
|
| + case IrOpcode::kMerge:
|
| + break;
|
| + case IrOpcode::kReturn:
|
| + // TODO(rossberg): check successor is End
|
| + break;
|
| + case IrOpcode::kThrow:
|
| + // TODO(rossberg): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kParameter:
|
| + // Parameters have no inputs.
|
| + CHECK_EQ(0, input_count);
|
| + break;
|
| + case IrOpcode::kInt32Constant:
|
| + case IrOpcode::kInt64Constant:
|
| + case IrOpcode::kFloat64Constant:
|
| + case IrOpcode::kExternalConstant:
|
| + case IrOpcode::kNumberConstant:
|
| + case IrOpcode::kHeapConstant:
|
| + // Constants have no inputs.
|
| + CHECK_EQ(0, input_count);
|
| + break;
|
| + case IrOpcode::kPhi: {
|
| + // Phi input count matches parent control node.
|
| + CHECK_EQ(1, control_count);
|
| + Node* control = NodeProperties::GetControlInput(node, 0);
|
| + CHECK_EQ(value_count, NodeProperties::GetControlInputCount(control));
|
| + break;
|
| + }
|
| + case IrOpcode::kEffectPhi: {
|
| + // EffectPhi input count matches parent control node.
|
| + CHECK_EQ(1, control_count);
|
| + Node* control = NodeProperties::GetControlInput(node, 0);
|
| + CHECK_EQ(effect_count, NodeProperties::GetControlInputCount(control));
|
| + break;
|
| + }
|
| + case IrOpcode::kLazyDeoptimization:
|
| + // TODO(jarin): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kDeoptimize:
|
| + // TODO(jarin): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kFrameState:
|
| + // TODO(jarin): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kCall:
|
| + // TODO(rossberg): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kContinuation:
|
| + // TODO(jarin): what are the constraints on these?
|
| + break;
|
| + case IrOpcode::kProjection: {
|
| + // Projection has an input that produces enough values.
|
| + int index = static_cast<Operator1<int>*>(node->op())->parameter();
|
| + Node* input = NodeProperties::GetValueInput(node, 0);
|
| + CHECK_GT(NodeProperties::GetValueOutputCount(input), index);
|
| + break;
|
| + }
|
| + default:
|
| + // TODO(rossberg): Check other node kinds.
|
| + break;
|
| + }
|
| +
|
| + if (from_start) {
|
| + reached_from_start.insert(node);
|
| + } else {
|
| + reached_from_end.insert(node);
|
| + }
|
| +
|
| + return GenericGraphVisit::CONTINUE;
|
| +}
|
| +
|
| +
|
| +void Verifier::Run(Graph* graph) {
|
| + Visitor visitor(graph->zone());
|
| +
|
| + visitor.from_start = true;
|
| + graph->VisitNodeUsesFromStart(&visitor);
|
| + visitor.from_start = false;
|
| + graph->VisitNodeInputsFromEnd(&visitor);
|
| +
|
| + // All control nodes reachable from end are reachable from start.
|
| + for (NodeSet::iterator it = visitor.reached_from_end.begin();
|
| + it != visitor.reached_from_end.end(); ++it) {
|
| + CHECK(!NodeProperties::IsControl(*it) ||
|
| + visitor.reached_from_start.count(*it));
|
| + }
|
| +}
|
| +}
|
| +}
|
| +} // namespace v8::internal::compiler
|
|
|