[turbofan] Initial attempt to cleanup Node and related classes.
authorbmeurer <bmeurer@chromium.org>
Fri, 16 Jan 2015 11:04:01 +0000 (03:04 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 16 Jan 2015 11:04:22 +0000 (11:04 +0000)
- Make Node::Inputs and Node::Uses mostly STL compliant.
- Get rid of some pre-C++11 crappiness.
- Start moving unit tests from cctest to unittests.
- TrimInputCount() now tries to reserve inputs slots for
  later appending.
- Fix numerous style guide violations.

TEST=cctest,unittests
R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/851263002

Cr-Commit-Position: refs/heads/master@{#26098}

28 files changed:
BUILD.gn
src/compiler/arm/instruction-selector-arm.cc
src/compiler/arm64/instruction-selector-arm64.cc
src/compiler/common-operator.cc
src/compiler/common-operator.h
src/compiler/control-reducer.cc
src/compiler/graph-reducer.cc
src/compiler/graph-visualizer.cc
src/compiler/ia32/instruction-selector-ia32.cc
src/compiler/instruction-selector.cc
src/compiler/js-inlining.cc
src/compiler/machine-operator-reducer.cc
src/compiler/mips/instruction-selector-mips.cc
src/compiler/mips64/instruction-selector-mips64.cc
src/compiler/node-properties.cc [new file with mode: 0644]
src/compiler/node-properties.h
src/compiler/node.cc
src/compiler/node.h
src/compiler/scheduler.cc
src/compiler/verifier.cc
src/compiler/x64/instruction-selector-x64.cc
test/cctest/compiler/test-control-reducer.cc
test/cctest/compiler/test-node.cc
test/unittests/compiler/graph-unittest.cc
test/unittests/compiler/node-properties-unittest.cc [new file with mode: 0644]
test/unittests/compiler/node-unittest.cc [new file with mode: 0644]
test/unittests/unittests.gyp
tools/gyp/v8.gyp

index a524ba1..bb0818c 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -546,6 +546,7 @@ source_set("v8_base") {
     "src/compiler/node-marker.cc",
     "src/compiler/node-marker.h",
     "src/compiler/node-matchers.h",
+    "src/compiler/node-properties.cc",
     "src/compiler/node-properties-inl.h",
     "src/compiler/node-properties.h",
     "src/compiler/node.cc",
index fb25c3b..64393dd 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/base/bits.h"
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -1035,9 +1036,9 @@ void InstructionSelector::VisitCall(Node* node) {
 
   // TODO(dcarney): might be possible to use claim/poke instead
   // Push any stack arguments.
-  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
-       input != buffer.pushed_nodes.rend(); input++) {
-    Emit(kArmPush, NULL, g.UseRegister(*input));
+  for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
+       ++i) {
+    Emit(kArmPush, nullptr, g.UseRegister(*i));
   }
 
   // Select the appropriate opcode based on the call type.
@@ -1180,14 +1181,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
           Node* const node = value->InputAt(0);
-          Node* const result = node->FindProjection(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (!result || selector->IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -1286,7 +1287,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kArmAdd, kArmAdd, &cont);
   }
@@ -1296,7 +1297,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kArmSub, kArmRsb, &cont);
   }
index 1d83a51..82c0bea 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -1310,14 +1311,14 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
-          Node* node = value->InputAt(0);
-          Node* result = node->FindProjection(0);
+          Node* const node = value->InputAt(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (result == NULL || IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -1461,7 +1462,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32,
                                          kArithmeticImm, &cont);
@@ -1472,7 +1473,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32,
                                          kArithmeticImm, &cont);
index 54059ac..e7d583f 100644 (file)
@@ -103,6 +103,12 @@ std::ostream& operator<<(std::ostream& os, FrameStateCallInfo const& info) {
 }
 
 
+size_t ProjectionIndexOf(const Operator* const op) {
+  DCHECK_EQ(IrOpcode::kProjection, op->opcode());
+  return OpParameter<size_t>(op);
+}
+
+
 #define CACHED_OP_LIST(V)                                  \
   V(Dead, Operator::kFoldable, 0, 0, 0, 0, 0, 1)           \
   V(End, Operator::kFoldable, 0, 0, 1, 0, 0, 0)            \
index 2505aff..d61e110 100644 (file)
@@ -153,6 +153,9 @@ size_t hash_value(FrameStateCallInfo const&);
 std::ostream& operator<<(std::ostream&, FrameStateCallInfo const&);
 
 
+size_t ProjectionIndexOf(const Operator* const);
+
+
 // Interface for building common operators that can be used at any level of IR,
 // including JavaScript, mid-level, and low-level.
 class CommonOperatorBuilder FINAL : public ZoneObject {
index b17e59d..877d1dc 100644 (file)
@@ -106,8 +106,9 @@ class ControlReducerImpl {
     marked.Push(start);
     marked.SetReachableFromStart(start);
 
-    // We use a stack of (Node, UseIter) pairs to avoid O(n^2) traversal.
-    typedef std::pair<Node*, UseIter> FwIter;
+    // We use a stack of (Node, Node::Uses::const_iterator) pairs to avoid
+    // O(n^2) traversal.
+    typedef std::pair<Node*, Node::Uses::const_iterator> FwIter;
     ZoneVector<FwIter> fw_stack(zone_);
     fw_stack.push_back(FwIter(start, start->uses().begin()));
 
@@ -420,8 +421,8 @@ class ControlReducerImpl {
     }
 
     Node* replacement = NULL;
-    Node::Inputs inputs = node->inputs();
-    for (InputIter it = inputs.begin(); n > 1; --n, ++it) {
+    auto const inputs = node->inputs();
+    for (auto it = inputs.begin(); n > 1; --n, ++it) {
       Node* input = *it;
       if (input->opcode() == IrOpcode::kDead) continue;  // ignore dead inputs.
       if (input != node && input != replacement) {       // non-redundant input.
index 9a6b121..91049a4 100644 (file)
@@ -154,9 +154,11 @@ void GraphReducer::ReduceTop() {
       // Otherwise {node} was replaced by a new node. Replace all old uses of
       // {node} with {replacement}. New nodes created by this reduction can
       // use {node}.
-      node->ReplaceUsesIf(
-          [node_count](Node* const node) { return node->id() < node_count; },
-          replacement);
+      for (Edge edge : node->use_edges()) {
+        if (edge.from()->id() < node_count) {
+          edge.UpdateTo(replacement);
+        }
+      }
       // Unlink {node} if it's no longer used.
       if (node->uses().empty()) {
         node->Kill();
index e018c7a..fe9c28e 100644 (file)
@@ -417,7 +417,8 @@ class GraphC1Visualizer {
   void PrintNodeId(Node* n);
   void PrintNode(Node* n);
   void PrintInputs(Node* n);
-  void PrintInputs(InputIter* i, int count, const char* prefix);
+  template <typename InputIterator>
+  void PrintInputs(InputIterator* i, int count, const char* prefix);
   void PrintType(Node* node);
 
   void PrintLiveRange(LiveRange* range, const char* type);
@@ -516,7 +517,8 @@ void GraphC1Visualizer::PrintNode(Node* n) {
 }
 
 
-void GraphC1Visualizer::PrintInputs(InputIter* i, int count,
+template <typename InputIterator>
+void GraphC1Visualizer::PrintInputs(InputIterator* i, int count,
                                     const char* prefix) {
   if (count > 0) {
     os_ << prefix;
index e237ebf..e3a8246 100644 (file)
@@ -734,11 +734,11 @@ void InstructionSelector::VisitCall(Node* node) {
   InitializeCallBuffer(node, &buffer, true, true);
 
   // Push any stack arguments.
-  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
-       input != buffer.pushed_nodes.rend(); input++) {
+  for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
+       ++i) {
     // TODO(titzer): handle pushing double parameters.
-    Emit(kIA32Push, NULL,
-         g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
+    Emit(kIA32Push, nullptr,
+         g.CanBeImmediate(*i) ? g.UseImmediate(*i) : g.Use(*i));
   }
 
   // Select the appropriate opcode based on the call type.
@@ -877,14 +877,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
-          Node* node = value->InputAt(0);
-          Node* result = node->FindProjection(0);
+          Node* const node = value->InputAt(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (result == NULL || selector->IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -959,7 +959,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kIA32Add, &cont);
   }
@@ -969,7 +969,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kIA32Sub, &cont);
   }
index e788329..3447c94 100644 (file)
@@ -337,8 +337,14 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
     if (buffer->descriptor->ReturnCount() == 1) {
       buffer->output_nodes.push_back(call);
     } else {
-      buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), NULL);
-      call->CollectProjections(&buffer->output_nodes);
+      buffer->output_nodes.resize(buffer->descriptor->ReturnCount(), nullptr);
+      for (auto use : call->uses()) {
+        if (use->opcode() != IrOpcode::kProjection) continue;
+        size_t const index = ProjectionIndexOf(use->op());
+        DCHECK_LT(index, buffer->output_nodes.size());
+        DCHECK_EQ(nullptr, buffer->output_nodes[index]);
+        buffer->output_nodes[index] = use;
+      }
     }
 
     // Filter out the outputs that aren't live because no projection uses them.
@@ -1000,10 +1006,10 @@ void InstructionSelector::VisitProjection(Node* node) {
   switch (value->opcode()) {
     case IrOpcode::kInt32AddWithOverflow:
     case IrOpcode::kInt32SubWithOverflow:
-      if (OpParameter<size_t>(node) == 0) {
+      if (ProjectionIndexOf(node->op()) == 0u) {
         Emit(kArchNop, g.DefineSameAsFirst(node), g.Use(value));
       } else {
-        DCHECK(OpParameter<size_t>(node) == 1u);
+        DCHECK(ProjectionIndexOf(node->op()) == 1u);
         MarkAsUsed(value);
       }
       break;
index d143382..32c381f 100644 (file)
@@ -407,10 +407,8 @@ void JSInliner::TryInlineJSCall(Node* call_node) {
           CreateArgumentsAdaptorFrameState(&call, function, info.zone());
     }
 
-    for (NodeVectorConstIter it = visitor.copies().begin();
-         it != visitor.copies().end(); ++it) {
-      Node* node = *it;
-      if (node != NULL && node->opcode() == IrOpcode::kFrameState) {
+    for (Node* node : visitor.copies()) {
+      if (node && node->opcode() == IrOpcode::kFrameState) {
         AddClosureToFrameState(node, function);
         NodeProperties::ReplaceFrameStateInput(node, outer_frame_state);
       }
index 9496e10..516daec 100644 (file)
@@ -130,7 +130,7 @@ Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
 Reduction MachineOperatorReducer::Reduce(Node* node) {
   switch (node->opcode()) {
     case IrOpcode::kProjection:
-      return ReduceProjection(OpParameter<size_t>(node), node->InputAt(0));
+      return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
     case IrOpcode::kWord32And:
       return ReduceWord32And(node);
     case IrOpcode::kWord32Or:
index 4d3577f..d684017 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/base/bits.h"
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -468,10 +469,10 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kMipsStackClaim | MiscField::encode(push_count), NULL);
   }
   int slot = buffer.pushed_nodes.size() - 1;
-  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
-       input != buffer.pushed_nodes.rend(); input++) {
-    Emit(kMipsStoreToStackSlot | MiscField::encode(slot), NULL,
-         g.UseRegister(*input));
+  for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
+       ++i) {
+    Emit(kMipsStoreToStackSlot | MiscField::encode(slot), nullptr,
+         g.UseRegister(*i));
     slot--;
   }
 
@@ -691,14 +692,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
           Node* const node = value->InputAt(0);
-          Node* const result = node->FindProjection(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (!result || selector->IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -778,7 +779,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kMipsAddOvf, &cont);
   }
@@ -788,7 +789,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kMipsSubOvf, &cont);
   }
index a92d311..c01d740 100644 (file)
@@ -5,6 +5,7 @@
 #include "src/base/bits.h"
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -648,10 +649,10 @@ void InstructionSelector::VisitCall(Node* node) {
     Emit(kMips64StackClaim | MiscField::encode(push_count), NULL);
   }
   int slot = buffer.pushed_nodes.size() - 1;
-  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
-       input != buffer.pushed_nodes.rend(); input++) {
-    Emit(kMips64StoreToStackSlot | MiscField::encode(slot), NULL,
-         g.UseRegister(*input));
+  for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
+       ++i) {
+    Emit(kMips64StoreToStackSlot | MiscField::encode(slot), nullptr,
+         g.UseRegister(*i));
     slot--;
   }
 
@@ -920,14 +921,14 @@ void VisitWordCompareZero(InstructionSelector* selector, Node* user,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
-          Node* node = value->InputAt(0);
-          Node* result = node->FindProjection(0);
+          Node* const node = value->InputAt(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (result == NULL || selector->IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -1000,7 +1001,7 @@ void InstructionSelector::VisitUint32LessThanOrEqual(Node* node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kMips64Dadd, &cont);
   }
@@ -1010,7 +1011,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kMips64Dsub, &cont);
   }
diff --git a/src/compiler/node-properties.cc b/src/compiler/node-properties.cc
new file mode 100644 (file)
index 0000000..f3e731f
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2015 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/common-operator.h"
+#include "src/compiler/node-properties.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+Node* NodeProperties::FindProjection(Node* node, size_t projection_index) {
+  for (auto use : node->uses()) {
+    if (use->opcode() == IrOpcode::kProjection &&
+        ProjectionIndexOf(use->op()) == projection_index) {
+      return use;
+    }
+  }
+  return nullptr;
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index 13f31d1..50a5ee4 100644 (file)
@@ -39,7 +39,9 @@ class NodeProperties {
   static inline void ReplaceFrameStateInput(Node* node, Node* frame_state);
   static inline void RemoveNonValueInputs(Node* node);
   static inline void ReplaceWithValue(Node* node, Node* value,
-                                      Node* effect = NULL);
+                                      Node* effect = nullptr);
+
+  static Node* FindProjection(Node* node, size_t projection_index);
 
   static inline bool IsTyped(Node* node);
   static inline Bounds GetBounds(Node* node);
index b86b0bd..1486d8a 100644 (file)
@@ -4,24 +4,12 @@
 
 #include "src/compiler/node.h"
 
+#include <algorithm>
+
 namespace v8 {
 namespace internal {
 namespace compiler {
 
-Node::Node(NodeId id, const Operator* op, int input_count,
-           int reserved_input_count)
-    : op_(op),
-      mark_(0),
-      id_(id),
-      bit_field_(InputCountField::encode(input_count) |
-                 ReservedInputCountField::encode(reserved_input_count) |
-                 HasAppendableInputsField::encode(false)),
-      first_use_(nullptr),
-      last_use_(nullptr) {
-  inputs_.static_ = reinterpret_cast<Input*>(this + 1);
-}
-
-
 Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
                 Node** inputs, bool has_extensible_inputs) {
   size_t node_size = sizeof(Node);
@@ -57,28 +45,67 @@ void Node::Kill() {
 }
 
 
-void Node::CollectProjections(NodeVector* projections) {
-  for (size_t i = 0; i < projections->size(); i++) {
-    (*projections)[i] = NULL;
+void Node::AppendInput(Zone* zone, Node* new_to) {
+  DCHECK_NOT_NULL(zone);
+  DCHECK_NOT_NULL(new_to);
+  Use* new_use = new (zone) Use;
+  Input new_input;
+  new_input.to = new_to;
+  new_input.use = new_use;
+  if (reserved_input_count() > 0) {
+    DCHECK(!has_appendable_inputs());
+    set_reserved_input_count(reserved_input_count() - 1);
+    inputs_.static_[input_count()] = new_input;
+  } else {
+    EnsureAppendableInputs(zone);
+    inputs_.appendable_->push_back(new_input);
   }
-  for (UseIter i = uses().begin(); i != uses().end(); ++i) {
-    if ((*i)->opcode() != IrOpcode::kProjection) continue;
-    size_t index = OpParameter<size_t>(*i);
-    DCHECK_LT(index, projections->size());
-    DCHECK_EQ(NULL, (*projections)[index]);
-    (*projections)[index] = *i;
+  new_use->input_index = input_count();
+  new_use->from = this;
+  new_to->AppendUse(new_use);
+  set_input_count(input_count() + 1);
+}
+
+
+void Node::InsertInput(Zone* zone, int index, Node* new_to) {
+  DCHECK_NOT_NULL(zone);
+  DCHECK_LE(0, index);
+  DCHECK_LT(index, InputCount());
+  AppendInput(zone, InputAt(InputCount() - 1));
+  for (int i = InputCount() - 1; i > index; --i) {
+    ReplaceInput(i, InputAt(i - 1));
   }
+  ReplaceInput(index, new_to);
 }
 
 
-Node* Node::FindProjection(size_t projection_index) {
-  for (UseIter i = uses().begin(); i != uses().end(); ++i) {
-    if ((*i)->opcode() == IrOpcode::kProjection &&
-        OpParameter<size_t>(*i) == projection_index) {
-      return *i;
-    }
+void Node::RemoveInput(int index) {
+  DCHECK_LE(0, index);
+  DCHECK_LT(index, InputCount());
+  for (; index < InputCount() - 1; ++index) {
+    ReplaceInput(index, InputAt(index + 1));
+  }
+  TrimInputCount(InputCount() - 1);
+}
+
+
+void Node::RemoveAllInputs() {
+  for (Edge edge : input_edges()) edge.UpdateTo(nullptr);
+}
+
+
+void Node::TrimInputCount(int new_input_count) {
+  DCHECK_LE(new_input_count, input_count());
+  if (new_input_count == input_count()) return;  // Nothing to do.
+  for (int index = new_input_count; index < input_count(); ++index) {
+    ReplaceInput(index, nullptr);
+  }
+  if (!has_appendable_inputs()) {
+    set_reserved_input_count(std::min<int>(
+        ReservedInputCountField::kMax,
+        reserved_input_count() + (input_count() - new_input_count)));
   }
-  return NULL;
+  set_input_count(new_input_count);
 }
 
 
@@ -94,11 +121,102 @@ int Node::UseCount() const {
 Node* Node::UseAt(int index) const {
   DCHECK_LE(0, index);
   DCHECK_LT(index, UseCount());
-  Use* current = first_use_;
+  const Use* use = first_use_;
   while (index-- != 0) {
-    current = current->next;
+    use = use->next;
+  }
+  return use->from;
+}
+
+
+void Node::ReplaceUses(Node* replace_to) {
+  for (Use* use = first_use_; use; use = use->next) {
+    use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
+  }
+  if (!replace_to->last_use_) {
+    DCHECK_EQ(nullptr, replace_to->first_use_);
+    replace_to->first_use_ = first_use_;
+    replace_to->last_use_ = last_use_;
+  } else if (first_use_) {
+    DCHECK_NOT_NULL(replace_to->first_use_);
+    replace_to->last_use_->next = first_use_;
+    first_use_->prev = replace_to->last_use_;
+    replace_to->last_use_ = last_use_;
+  }
+  first_use_ = nullptr;
+  last_use_ = nullptr;
+}
+
+
+void Node::Input::Update(Node* new_to) {
+  Node* old_to = this->to;
+  if (new_to == old_to) return;  // Nothing to do.
+  // Snip out the use from where it used to be
+  if (old_to) {
+    old_to->RemoveUse(use);
+  }
+  to = new_to;
+  // And put it into the new node's use list.
+  if (new_to) {
+    new_to->AppendUse(use);
+  } else {
+    use->next = nullptr;
+    use->prev = nullptr;
+  }
+}
+
+
+Node::Node(NodeId id, const Operator* op, int input_count,
+           int reserved_input_count)
+    : op_(op),
+      mark_(0),
+      id_(id),
+      bit_field_(InputCountField::encode(input_count) |
+                 ReservedInputCountField::encode(reserved_input_count) |
+                 HasAppendableInputsField::encode(false)),
+      first_use_(nullptr),
+      last_use_(nullptr) {
+  inputs_.static_ = reinterpret_cast<Input*>(this + 1);
+}
+
+
+void Node::EnsureAppendableInputs(Zone* zone) {
+  if (!has_appendable_inputs()) {
+    void* deque_buffer = zone->New(sizeof(InputDeque));
+    InputDeque* deque = new (deque_buffer) InputDeque(zone);
+    for (int i = 0; i < input_count(); ++i) {
+      deque->push_back(inputs_.static_[i]);
+    }
+    inputs_.appendable_ = deque;
+    set_has_appendable_inputs(true);
+  }
+}
+
+
+void Node::AppendUse(Use* const use) {
+  use->next = nullptr;
+  use->prev = last_use_;
+  if (last_use_) {
+    last_use_->next = use;
+  } else {
+    first_use_ = use;
+  }
+  last_use_ = use;
+}
+
+
+void Node::RemoveUse(Use* const use) {
+  if (use == last_use_) {
+    last_use_ = use->prev;
+  }
+  if (use->prev) {
+    use->prev->next = use->next;
+  } else {
+    first_use_ = use->next;
+  }
+  if (use->next) {
+    use->next->prev = use->prev;
   }
-  return current->from;
 }
 
 
@@ -115,6 +233,46 @@ std::ostream& operator<<(std::ostream& os, const Node& n) {
   return os;
 }
 
+
+Node::InputEdges::iterator Node::InputEdges::iterator::operator++(int n) {
+  iterator result(*this);
+  ++(*this);
+  return result;
+}
+
+
+bool Node::InputEdges::empty() const { return begin() == end(); }
+
+
+Node::Inputs::const_iterator Node::Inputs::const_iterator::operator++(int n) {
+  const_iterator result(*this);
+  ++(*this);
+  return result;
+}
+
+
+bool Node::Inputs::empty() const { return begin() == end(); }
+
+
+Node::UseEdges::iterator Node::UseEdges::iterator::operator++(int n) {
+  iterator result(*this);
+  ++(*this);
+  return result;
+}
+
+
+bool Node::UseEdges::empty() const { return begin() == end(); }
+
+
+Node::Uses::const_iterator Node::Uses::const_iterator::operator++(int n) {
+  const_iterator result(*this);
+  ++(*this);
+  return result;
+}
+
+
+bool Node::Uses::empty() const { return begin() == end(); }
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 9d3a2b0..f8b3329 100644 (file)
@@ -5,14 +5,9 @@
 #ifndef V8_COMPILER_NODE_H_
 #define V8_COMPILER_NODE_H_
 
-#include <deque>
-#include <vector>
-
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/types-inl.h"
-#include "src/zone.h"
-#include "src/zone-allocator.h"
 #include "src/zone-containers.h"
 
 namespace v8 {
@@ -46,11 +41,11 @@ typedef int32_t NodeId;
 // by the Node's id.
 class Node FINAL {
  public:
-  bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; }
-  void Kill();
+  static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
+                   Node** inputs, bool has_extensible_inputs);
 
-  void CollectProjections(ZoneVector<Node*>* projections);
-  Node* FindProjection(size_t projection_index);
+  bool IsDead() const { return InputCount() > 0 && !InputAt(0); }
+  void Kill();
 
   const Operator* op() const { return op_; }
   void set_op(const Operator* op) { op_ = op; }
@@ -64,25 +59,25 @@ class Node FINAL {
 
   int InputCount() const { return input_count(); }
   Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; }
-  inline void ReplaceInput(int index, Node* new_input);
-  inline void AppendInput(Zone* zone, Node* new_input);
-  inline void InsertInput(Zone* zone, int index, Node* new_input);
-  inline void RemoveInput(int index);
+  inline void ReplaceInput(int index, Node* new_to);
+  void AppendInput(Zone* zone, Node* new_to);
+  void InsertInput(Zone* zone, int index, Node* new_to);
+  void RemoveInput(int index);
+  void RemoveAllInputs();
+  void TrimInputCount(int new_input_count);
 
   int UseCount() const;
   Node* UseAt(int index) const;
-  inline void ReplaceUses(Node* replace_to);
-  template <class UnaryPredicate>
-  inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to);
-  inline void RemoveAllInputs();
-
-  inline void TrimInputCount(int input_count);
+  void ReplaceUses(Node* replace_to);
 
-  class InputEdges {
+  class InputEdges FINAL {
    public:
+    typedef Edge value_type;
+
     class iterator;
-    iterator begin() const;
-    iterator end() const;
+    inline iterator begin() const;
+    inline iterator end() const;
+
     bool empty() const;
 
     explicit InputEdges(Node* node) : node_(node) {}
@@ -91,11 +86,16 @@ class Node FINAL {
     Node* node_;
   };
 
-  class Inputs {
+  InputEdges input_edges() { return InputEdges(this); }
+
+  class Inputs FINAL {
    public:
-    class iterator;
-    iterator begin() const;
-    iterator end() const;
+    typedef Node* value_type;
+
+    class const_iterator;
+    inline const_iterator begin() const;
+    inline const_iterator end() const;
+
     bool empty() const;
 
     explicit Inputs(Node* node) : node_(node) {}
@@ -105,13 +105,15 @@ class Node FINAL {
   };
 
   Inputs inputs() { return Inputs(this); }
-  InputEdges input_edges() { return InputEdges(this); }
 
-  class UseEdges {
+  class UseEdges FINAL {
    public:
+    typedef Edge value_type;
+
     class iterator;
-    iterator begin() const;
-    iterator end() const;
+    inline iterator begin() const;
+    inline iterator end() const;
+
     bool empty() const;
 
     explicit UseEdges(Node* node) : node_(node) {}
@@ -120,11 +122,16 @@ class Node FINAL {
     Node* node_;
   };
 
-  class Uses {
+  UseEdges use_edges() { return UseEdges(this); }
+
+  class Uses FINAL {
    public:
-    class iterator;
-    iterator begin() const;
-    iterator end() const;
+    typedef Node* value_type;
+
+    class const_iterator;
+    inline const_iterator begin() const;
+    inline const_iterator end() const;
+
     bool empty() const;
 
     explicit Uses(Node* node) : node_(node) {}
@@ -134,26 +141,21 @@ class Node FINAL {
   };
 
   Uses uses() { return Uses(this); }
-  UseEdges use_edges() { return UseEdges(this); }
-
-  bool OwnedBy(Node* owner) const;
 
-  static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
-                   Node** inputs, bool has_extensible_inputs);
-
- protected:
-  friend class Graph;
-  friend class Edge;
+  // Returns true if {owner} is the user of {this} node.
+  bool OwnedBy(Node* owner) const {
+    return first_use_ && first_use_->from == owner && !first_use_->next;
+  }
 
-  class Use : public ZoneObject {
-   public:
+ private:
+  struct Use FINAL : public ZoneObject {
     Node* from;
     Use* next;
     Use* prev;
     int input_index;
   };
 
-  class Input {
+  class Input FINAL {
    public:
     Node* to;
     Use* use;
@@ -161,7 +163,10 @@ class Node FINAL {
     void Update(Node* new_to);
   };
 
-  void EnsureAppendableInputs(Zone* zone);
+  inline Node(NodeId id, const Operator* op, int input_count,
+              int reserve_input_count);
+
+  inline void EnsureAppendableInputs(Zone* zone);
 
   Input* GetInputRecordPtr(int index) const {
     if (has_appendable_inputs()) {
@@ -171,20 +176,13 @@ class Node FINAL {
     }
   }
 
-  inline void AppendUse(Use* use);
-  inline void RemoveUse(Use* use);
+  inline void AppendUse(Use* const use);
+  inline void RemoveUse(Use* const use);
 
   void* operator new(size_t, void* location) { return location; }
 
- private:
-  inline Node(NodeId id, const Operator* op, int input_count,
-              int reserve_input_count);
-
   typedef ZoneDeque<Input> InputDeque;
 
-  friend class NodeMarkerBase;
-  friend class NodeProperties;
-
   // Only NodeProperties should manipulate the bounds.
   Bounds bounds() { return bounds_; }
   void set_bounds(Bounds b) { bounds_ = b; }
@@ -224,7 +222,7 @@ class Node FINAL {
   const Operator* op_;
   Bounds bounds_;
   Mark mark_;
-  NodeId id_;
+  NodeId const id_;
   unsigned bit_field_;
   union {
     // When a node is initially allocated, it uses a static buffer to hold its
@@ -237,20 +235,40 @@ class Node FINAL {
   Use* first_use_;
   Use* last_use_;
 
+  friend class Edge;
+  friend class NodeMarkerBase;
+  friend class NodeProperties;
+
   DISALLOW_COPY_AND_ASSIGN(Node);
 };
 
 
+std::ostream& operator<<(std::ostream& os, const Node& n);
+
+
+// Typedefs to shorten commonly used Node containers.
+typedef ZoneDeque<Node*> NodeDeque;
+typedef ZoneVector<Node*> NodeVector;
+typedef ZoneVector<NodeVector> NodeVectorVector;
+
+
+// Helper to extract parameters from Operator1<*> nodes.
+template <typename T>
+static inline const T& OpParameter(const Node* node) {
+  return OpParameter<T>(node->op());
+}
+
+
 // An encapsulation for information associated with a single use of node as a
 // input from another node, allowing access to both the defining node and
 // the node having the input.
-class Edge {
+class Edge FINAL {
  public:
   Node* from() const { return input_->use->from; }
   Node* to() const { return input_->to; }
   int index() const {
-    int index = input_->use->input_index;
-    DCHECK(index < input_->use->from->input_count());
+    int const index = input_->use->input_index;
+    DCHECK_LT(index, input_->use->from->input_count());
     return index;
   }
 
@@ -260,59 +278,51 @@ class Edge {
   void UpdateTo(Node* new_to) { input_->Update(new_to); }
 
  private:
-  friend class Node::Uses::iterator;
-  friend class Node::Inputs::iterator;
   friend class Node::UseEdges::iterator;
   friend class Node::InputEdges::iterator;
 
-  explicit Edge(Node::Input* input) : input_(input) {}
+  explicit Edge(Node::Input* input) : input_(input) { DCHECK_NOT_NULL(input); }
 
-  Node::Input* input_;
+  Node::Input* const input_;
 };
 
 
-// A forward iterator to visit the edges for the input dependencies of a node..
-class Node::InputEdges::iterator {
+// A forward iterator to visit the edges for the input dependencies of a node.
+class Node::InputEdges::iterator FINAL {
  public:
   typedef std::forward_iterator_tag iterator_category;
   typedef int difference_type;
   typedef Edge value_type;
   typedef Edge* pointer;
   typedef Edge& reference;
-  iterator(const Node::InputEdges::iterator& other)  // NOLINT
-      : input_(other.input_) {}
-  iterator() : input_(NULL) {}
+
+  iterator() : input_(nullptr) {}
+  iterator(const iterator& other) : input_(other.input_) {}
 
   Edge operator*() const { return Edge(input_); }
-  bool operator==(const iterator& other) const { return Equals(other); }
-  bool operator!=(const iterator& other) const { return !Equals(other); }
+  bool operator==(const iterator& other) const {
+    return input_ == other.input_;
+  }
+  bool operator!=(const iterator& other) const { return !(*this == other); }
   iterator& operator++() {
-    DCHECK(input_ != NULL);
-    Edge edge(input_);
-    Node* from = edge.from();
-    SetInput(from, input_->use->input_index + 1);
+    SetInput(Edge(input_).from(), input_->use->input_index + 1);
     return *this;
   }
-  iterator operator++(int) {
-    iterator result(*this);
-    ++(*this);
-    return result;
-  }
+  iterator operator++(int);
 
  private:
   friend class Node;
 
-  explicit iterator(Node* from, int index = 0) : input_(NULL) {
+  explicit iterator(Node* from, int index = 0) : input_(nullptr) {
     SetInput(from, index);
   }
 
-  bool Equals(const iterator& other) const { return other.input_ == input_; }
   void SetInput(Node* from, int index) {
     DCHECK(index >= 0 && index <= from->InputCount());
     if (index < from->InputCount()) {
       input_ = from->GetInputRecordPtr(index);
     } else {
-      input_ = NULL;
+      input_ = nullptr;
     }
   }
 
@@ -320,8 +330,18 @@ class Node::InputEdges::iterator {
 };
 
 
+Node::InputEdges::iterator Node::InputEdges::begin() const {
+  return Node::InputEdges::iterator(this->node_, 0);
+}
+
+
+Node::InputEdges::iterator Node::InputEdges::end() const {
+  return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
+}
+
+
 // A forward iterator to visit the inputs of a node.
-class Node::Inputs::iterator {
+class Node::Inputs::const_iterator FINAL {
  public:
   typedef std::forward_iterator_tag iterator_category;
   typedef int difference_type;
@@ -329,319 +349,133 @@ class Node::Inputs::iterator {
   typedef Node** pointer;
   typedef Node*& reference;
 
-  iterator(const Node::Inputs::iterator& other)  // NOLINT
-      : iter_(other.iter_) {}
+  const_iterator(const const_iterator& other) : iter_(other.iter_) {}
 
   Node* operator*() const { return (*iter_).to(); }
-  bool operator==(const iterator& other) const { return Equals(other); }
-  bool operator!=(const iterator& other) const { return !Equals(other); }
-  iterator& operator++() {
+  bool operator==(const const_iterator& other) const {
+    return iter_ == other.iter_;
+  }
+  bool operator!=(const const_iterator& other) const {
+    return !(*this == other);
+  }
+  const_iterator& operator++() {
     ++iter_;
     return *this;
   }
-  iterator operator++(int) {
-    iterator result(*this);
-    ++(*this);
-    return result;
-  }
-
+  const_iterator operator++(int);
 
  private:
   friend class Node::Inputs;
 
-  explicit iterator(Node* node, int index) : iter_(node, index) {}
-
-  bool Equals(const iterator& other) const { return other.iter_ == iter_; }
+  const_iterator(Node* node, int index) : iter_(node, index) {}
 
   Node::InputEdges::iterator iter_;
 };
 
+
+Node::Inputs::const_iterator Node::Inputs::begin() const {
+  return const_iterator(this->node_, 0);
+}
+
+
+Node::Inputs::const_iterator Node::Inputs::end() const {
+  return const_iterator(this->node_, this->node_->InputCount());
+}
+
+
 // A forward iterator to visit the uses edges of a node. The edges are returned
 // in
 // the order in which they were added as inputs.
-class Node::UseEdges::iterator {
+class Node::UseEdges::iterator FINAL {
  public:
-  iterator(const Node::UseEdges::iterator& other)  // NOLINT
-      : current_(other.current_),
-        next_(other.next_) {}
+  iterator(const iterator& other)
+      : current_(other.current_), next_(other.next_) {}
 
-  Edge operator*() const { return Edge(CurrentInput()); }
+  Edge operator*() const {
+    return Edge(current_->from->GetInputRecordPtr(current_->input_index));
+  }
 
-  bool operator==(const iterator& other) { return Equals(other); }
-  bool operator!=(const iterator& other) { return !Equals(other); }
+  bool operator==(const iterator& other) const {
+    return current_ == other.current_;
+  }
+  bool operator!=(const iterator& other) const { return !(*this == other); }
   iterator& operator++() {
-    DCHECK(current_ != NULL);
+    DCHECK_NOT_NULL(current_);
     current_ = next_;
-    next_ = (current_ == NULL) ? NULL : current_->next;
+    next_ = current_ ? current_->next : nullptr;
     return *this;
   }
-  iterator operator++(int) {
-    iterator result(*this);
-    ++(*this);
-    return result;
-  }
+  iterator operator++(int);
 
  private:
   friend class Node::UseEdges;
 
-  iterator() : current_(NULL), next_(NULL) {}
+  iterator() : current_(nullptr), next_(nullptr) {}
   explicit iterator(Node* node)
       : current_(node->first_use_),
-        next_(current_ == NULL ? NULL : current_->next) {}
-
-  bool Equals(const iterator& other) const {
-    return other.current_ == current_;
-  }
-
-  Input* CurrentInput() const {
-    return current_->from->GetInputRecordPtr(current_->input_index);
-  }
+        next_(current_ ? current_->next : nullptr) {}
 
   Node::Use* current_;
   Node::Use* next_;
 };
 
 
-// A forward iterator to visit the uses of a node. The uses are returned in
-// the order in which they were added as inputs.
-class Node::Uses::iterator {
- public:
-  iterator(const Node::Uses::iterator& other)  // NOLINT
-      : current_(other.current_) {}
-
-  Node* operator*() { return current_->from; }
-
-  bool operator==(const iterator& other) { return other.current_ == current_; }
-  bool operator!=(const iterator& other) { return other.current_ != current_; }
-  iterator& operator++() {
-    DCHECK(current_ != NULL);
-    current_ = current_->next;
-    return *this;
-  }
-
- private:
-  friend class Node::Uses;
-
-  iterator() : current_(NULL) {}
-  explicit iterator(Node* node) : current_(node->first_use_) {}
-
-  Input* CurrentInput() const {
-    return current_->from->GetInputRecordPtr(current_->input_index);
-  }
-
-  Node::Use* current_;
-};
-
-
-std::ostream& operator<<(std::ostream& os, const Node& n);
-
-typedef ZoneDeque<Node*> NodeDeque;
-
-typedef ZoneVector<Node*> NodeVector;
-typedef NodeVector::iterator NodeVectorIter;
-typedef NodeVector::const_iterator NodeVectorConstIter;
-typedef NodeVector::reverse_iterator NodeVectorRIter;
-
-typedef ZoneVector<NodeVector> NodeVectorVector;
-typedef NodeVectorVector::iterator NodeVectorVectorIter;
-typedef NodeVectorVector::reverse_iterator NodeVectorVectorRIter;
-
-typedef Node::Uses::iterator UseIter;
-typedef Node::Inputs::iterator InputIter;
-
-// Helper to extract parameters from Operator1<*> nodes.
-template <typename T>
-static inline const T& OpParameter(const Node* node) {
-  return OpParameter<T>(node->op());
-}
-
-inline Node::InputEdges::iterator Node::InputEdges::begin() const {
-  return Node::InputEdges::iterator(this->node_, 0);
-}
-
-inline Node::InputEdges::iterator Node::InputEdges::end() const {
-  return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
-}
-
-inline Node::Inputs::iterator Node::Inputs::begin() const {
-  return Node::Inputs::iterator(this->node_, 0);
-}
-
-inline Node::Inputs::iterator Node::Inputs::end() const {
-  return Node::Inputs::iterator(this->node_, this->node_->InputCount());
-}
-
-inline Node::UseEdges::iterator Node::UseEdges::begin() const {
+Node::UseEdges::iterator Node::UseEdges::begin() const {
   return Node::UseEdges::iterator(this->node_);
 }
 
-inline Node::UseEdges::iterator Node::UseEdges::end() const {
-  return Node::UseEdges::iterator();
-}
 
-inline Node::Uses::iterator Node::Uses::begin() const {
-  return Node::Uses::iterator(this->node_);
+Node::UseEdges::iterator Node::UseEdges::end() const {
+  return Node::UseEdges::iterator();
 }
 
-inline Node::Uses::iterator Node::Uses::end() const {
-  return Node::Uses::iterator();
-}
 
-inline bool Node::InputEdges::empty() const { return begin() == end(); }
-inline bool Node::Uses::empty() const { return begin() == end(); }
-inline bool Node::UseEdges::empty() const { return begin() == end(); }
-inline bool Node::Inputs::empty() const { return begin() == end(); }
+// A forward iterator to visit the uses of a node. The uses are returned in
+// the order in which they were added as inputs.
+class Node::Uses::const_iterator FINAL {
+ public:
+  typedef std::forward_iterator_tag iterator_category;
+  typedef int difference_type;
+  typedef Node* value_type;
+  typedef Node** pointer;
+  typedef Node*& reference;
 
-inline void Node::ReplaceUses(Node* replace_to) {
-  for (Use* use = first_use_; use != NULL; use = use->next) {
-    use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
-  }
-  if (replace_to->last_use_ == NULL) {
-    DCHECK_EQ(NULL, replace_to->first_use_);
-    replace_to->first_use_ = first_use_;
-    replace_to->last_use_ = last_use_;
-  } else if (first_use_ != NULL) {
-    DCHECK_NE(NULL, replace_to->first_use_);
-    replace_to->last_use_->next = first_use_;
-    first_use_->prev = replace_to->last_use_;
-    replace_to->last_use_ = last_use_;
-  }
-  first_use_ = NULL;
-  last_use_ = NULL;
-}
+  const_iterator(const const_iterator& other) : current_(other.current_) {}
 
-template <class UnaryPredicate>
-inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) {
-  for (Use* use = first_use_; use != NULL;) {
-    Use* next = use->next;
-    if (pred(use->from)) {
-      RemoveUse(use);
-      replace_to->AppendUse(use);
-      use->from->GetInputRecordPtr(use->input_index)->to = replace_to;
-    }
-    use = next;
+  Node* operator*() const { return current_->from; }
+  bool operator==(const const_iterator& other) const {
+    return other.current_ == current_;
   }
-}
-
-inline void Node::RemoveAllInputs() {
-  for (Edge edge : input_edges()) {
-    edge.UpdateTo(NULL);
+  bool operator!=(const const_iterator& other) const {
+    return other.current_ != current_;
   }
-}
-
-inline void Node::TrimInputCount(int new_input_count) {
-  if (new_input_count == input_count()) return;  // Nothing to do.
-
-  DCHECK(new_input_count < input_count());
-
-  // Update inline inputs.
-  for (int i = new_input_count; i < input_count(); i++) {
-    Node::Input* input = GetInputRecordPtr(i);
-    input->Update(NULL);
+  const_iterator& operator++() {
+    DCHECK_NOT_NULL(current_);
+    current_ = current_->next;
+    return *this;
   }
-  set_input_count(new_input_count);
-}
+  const_iterator operator++(int);
 
-inline void Node::ReplaceInput(int index, Node* new_to) {
-  Input* input = GetInputRecordPtr(index);
-  input->Update(new_to);
-}
+ private:
+  friend class Node::Uses;
 
-inline void Node::Input::Update(Node* new_to) {
-  Node* old_to = this->to;
-  if (new_to == old_to) return;  // Nothing to do.
-  // Snip out the use from where it used to be
-  if (old_to != NULL) {
-    old_to->RemoveUse(use);
-  }
-  to = new_to;
-  // And put it into the new node's use list.
-  if (new_to != NULL) {
-    new_to->AppendUse(use);
-  } else {
-    use->next = NULL;
-    use->prev = NULL;
-  }
-}
+  const_iterator() : current_(nullptr) {}
+  explicit const_iterator(Node* node) : current_(node->first_use_) {}
 
-inline void Node::EnsureAppendableInputs(Zone* zone) {
-  if (!has_appendable_inputs()) {
-    void* deque_buffer = zone->New(sizeof(InputDeque));
-    InputDeque* deque = new (deque_buffer) InputDeque(zone);
-    for (int i = 0; i < input_count(); ++i) {
-      deque->push_back(inputs_.static_[i]);
-    }
-    inputs_.appendable_ = deque;
-    set_has_appendable_inputs(true);
-  }
-}
+  Node::Use* current_;
+};
 
-inline void Node::AppendInput(Zone* zone, Node* to_append) {
-  Use* new_use = new (zone) Use;
-  Input new_input;
-  new_input.to = to_append;
-  new_input.use = new_use;
-  if (reserved_input_count() > 0) {
-    DCHECK(!has_appendable_inputs());
-    set_reserved_input_count(reserved_input_count() - 1);
-    inputs_.static_[input_count()] = new_input;
-  } else {
-    EnsureAppendableInputs(zone);
-    inputs_.appendable_->push_back(new_input);
-  }
-  new_use->input_index = input_count();
-  new_use->from = this;
-  to_append->AppendUse(new_use);
-  set_input_count(input_count() + 1);
-}
 
-inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) {
-  DCHECK(index >= 0 && index < InputCount());
-  // TODO(turbofan): Optimize this implementation!
-  AppendInput(zone, InputAt(InputCount() - 1));
-  for (int i = InputCount() - 1; i > index; --i) {
-    ReplaceInput(i, InputAt(i - 1));
-  }
-  ReplaceInput(index, to_insert);
+Node::Uses::const_iterator Node::Uses::begin() const {
+  return const_iterator(this->node_);
 }
 
-inline void Node::RemoveInput(int index) {
-  DCHECK(index >= 0 && index < InputCount());
-  // TODO(turbofan): Optimize this implementation!
-  for (; index < InputCount() - 1; ++index) {
-    ReplaceInput(index, InputAt(index + 1));
-  }
-  TrimInputCount(InputCount() - 1);
-}
 
-inline void Node::AppendUse(Use* use) {
-  use->next = NULL;
-  use->prev = last_use_;
-  if (last_use_ == NULL) {
-    first_use_ = use;
-  } else {
-    last_use_->next = use;
-  }
-  last_use_ = use;
-}
+Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
 
-inline void Node::RemoveUse(Use* use) {
-  if (last_use_ == use) {
-    last_use_ = use->prev;
-  }
-  if (use->prev != NULL) {
-    use->prev->next = use->next;
-  } else {
-    first_use_ = use->next;
-  }
-  if (use->next != NULL) {
-    use->next->prev = use->prev;
-  }
-}
 
-inline bool Node::OwnedBy(Node* owner) const {
-  return first_use_ != NULL && first_use_->from == owner &&
-         first_use_->next == NULL;
+void Node::ReplaceInput(int index, Node* new_to) {
+  GetInputRecordPtr(index)->Update(new_to);
 }
 
 }  // namespace compiler
index 6ec2295..cb11bec 100644 (file)
@@ -127,11 +127,10 @@ void Scheduler::UpdatePlacement(Node* node, Placement placement) {
 #undef DEFINE_CONTROL_CASE
       {
         // Control nodes force coupled uses to be placed.
-        Node::Uses uses = node->uses();
-        for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
-          if (GetPlacement(*i) == Scheduler::kCoupled) {
-            DCHECK_EQ(node, NodeProperties::GetControlInput(*i));
-            UpdatePlacement(*i, placement);
+        for (auto use : node->uses()) {
+          if (GetPlacement(use) == Scheduler::kCoupled) {
+            DCHECK_EQ(node, NodeProperties::GetControlInput(use));
+            UpdatePlacement(use, placement);
           }
         }
         break;
@@ -1131,8 +1130,8 @@ class ScheduleEarlyNodeVisitor {
 
   // Run the schedule early algorithm on a set of fixed root nodes.
   void Run(NodeVector* roots) {
-    for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
-      queue_.push(*i);
+    for (Node* const root : *roots) {
+      queue_.push(root);
       while (!queue_.empty()) {
         VisitNode(queue_.front());
         queue_.pop();
@@ -1160,9 +1159,8 @@ class ScheduleEarlyNodeVisitor {
 
     // Propagate schedule early position.
     DCHECK(data->minimum_block_ != NULL);
-    Node::Uses uses = node->uses();
-    for (Node::Uses::iterator i = uses.begin(); i != uses.end(); ++i) {
-      PropagateMinimumPositionToNode(data->minimum_block_, *i);
+    for (auto use : node->uses()) {
+      PropagateMinimumPositionToNode(data->minimum_block_, use);
     }
   }
 
@@ -1236,8 +1234,8 @@ class ScheduleLateNodeVisitor {
 
   // Run the schedule late algorithm on a set of fixed root nodes.
   void Run(NodeVector* roots) {
-    for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
-      ProcessQueue(*i);
+    for (Node* const root : *roots) {
+      ProcessQueue(root);
     }
   }
 
@@ -1404,7 +1402,7 @@ void Scheduler::SealFinalSchedule() {
   for (NodeVector& nodes : scheduled_nodes_) {
     BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++);
     BasicBlock* block = schedule_->GetBlockById(id);
-    for (NodeVectorRIter i = nodes.rbegin(); i != nodes.rend(); ++i) {
+    for (auto i = nodes.rbegin(); i != nodes.rend(); ++i) {
       schedule_->AddNode(block, *i);
     }
   }
@@ -1472,9 +1470,9 @@ void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
   Trace("Move planned nodes from B%d to B%d\n", from->id().ToInt(),
         to->id().ToInt());
   NodeVector* nodes = &(scheduled_nodes_[from->id().ToSize()]);
-  for (NodeVectorIter i = nodes->begin(); i != nodes->end(); ++i) {
-    schedule_->SetBlockForNode(to, *i);
-    scheduled_nodes_[to->id().ToSize()].push_back(*i);
+  for (Node* const node : *nodes) {
+    schedule_->SetBlockForNode(to, node);
+    scheduled_nodes_[to->id().ToSize()].push_back(node);
   }
   nodes->clear();
 }
index 116989d..aa5c9a4 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/compiler/verifier.h"
 
+#include <algorithm>
 #include <deque>
 #include <queue>
 #include <sstream>
@@ -28,20 +29,14 @@ 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;
+  auto const uses = def->uses();
+  return std::find(uses.begin(), uses.end(), use) != uses.end();
 }
 
 
 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;
+  auto const inputs = use->inputs();
+  return std::find(inputs.begin(), inputs.end(), def) != inputs.end();
 }
 
 
@@ -205,13 +200,12 @@ void Verifier::Visitor::Pre(Node* node) {
       UNREACHABLE();
     case IrOpcode::kBranch: {
       // Branch uses are IfTrue and IfFalse.
-      Node::Uses uses = node->uses();
       int count_true = 0, count_false = 0;
-      for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
-        CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
-              (*it)->opcode() == IrOpcode::kIfFalse);
-        if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
-        if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
+      for (auto use : node->uses()) {
+        CHECK(use->opcode() == IrOpcode::kIfTrue ||
+              use->opcode() == IrOpcode::kIfFalse);
+        if (use->opcode() == IrOpcode::kIfTrue) ++count_true;
+        if (use->opcode() == IrOpcode::kIfFalse) ++count_false;
       }
       CHECK(count_true == 1 && count_false == 1);
       // Type is empty.
@@ -314,7 +308,7 @@ void Verifier::Visitor::Pre(Node* node) {
       break;
     case IrOpcode::kProjection: {
       // Projection has an input that produces enough values.
-      int index = static_cast<int>(OpParameter<size_t>(node->op()));
+      int index = static_cast<int>(ProjectionIndexOf(node->op()));
       Node* input = NodeProperties::GetValueInput(node, 0);
       CHECK_GT(input->op()->ValueOutputCount(), index);
       // Type can be anything.
index bf6b170..c1f2e0c 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "src/compiler/instruction-selector-impl.h"
 #include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
 
 namespace v8 {
 namespace internal {
@@ -938,11 +939,11 @@ void InstructionSelector::VisitCall(Node* node) {
   InitializeCallBuffer(node, &buffer, true, true);
 
   // Push any stack arguments.
-  for (NodeVectorRIter input = buffer.pushed_nodes.rbegin();
-       input != buffer.pushed_nodes.rend(); input++) {
+  for (auto i = buffer.pushed_nodes.rbegin(); i != buffer.pushed_nodes.rend();
+       ++i) {
     // TODO(titzer): handle pushing double parameters.
-    Emit(kX64Push, NULL,
-         g.CanBeImmediate(*input) ? g.UseImmediate(*input) : g.Use(*input));
+    Emit(kX64Push, nullptr,
+         g.CanBeImmediate(*i) ? g.UseImmediate(*i) : g.Use(*i));
   }
 
   // Select the appropriate opcode based on the call type.
@@ -1111,14 +1112,14 @@ void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
       case IrOpcode::kProjection:
         // Check if this is the overflow output projection of an
         // <Operation>WithOverflow node.
-        if (OpParameter<size_t>(value) == 1u) {
+        if (ProjectionIndexOf(value->op()) == 1u) {
           // We cannot combine the <Operation>WithOverflow with this branch
           // unless the 0th projection (the use of the actual value of the
           // <Operation> is either NULL, which means there's no use of the
           // actual value, or was already defined, which means it is scheduled
           // *AFTER* this branch).
-          Node* node = value->InputAt(0);
-          Node* result = node->FindProjection(0);
+          Node* const node = value->InputAt(0);
+          Node* const result = NodeProperties::FindProjection(node, 0);
           if (result == NULL || IsDefined(result)) {
             switch (node->opcode()) {
               case IrOpcode::kInt32AddWithOverflow:
@@ -1248,7 +1249,7 @@ void InstructionSelector::VisitWord64Equal(Node* const node) {
 
 
 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     VisitBinop(this, node, kX64Add32, &cont);
   }
@@ -1258,7 +1259,7 @@ void InstructionSelector::VisitInt32AddWithOverflow(Node* node) {
 
 
 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) {
-  if (Node* ovf = node->FindProjection(1)) {
+  if (Node* ovf = NodeProperties::FindProjection(node, 1)) {
     FlagsContinuation cont(kOverflow, ovf);
     return VisitBinop(this, node, kX64Sub32, &cont);
   }
index 03aa50b..61dad29 100644 (file)
@@ -52,10 +52,8 @@ static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
 
 
 bool IsUsedBy(Node* a, Node* b) {
-  for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
-    if (b == *i) return true;
-  }
-  return false;
+  auto const uses = a->uses();
+  return std::find(uses.begin(), uses.end(), b) != uses.end();
 }
 
 
index eafabd3..23238da 100644 (file)
@@ -16,136 +16,26 @@ using namespace v8::internal::compiler;
 static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
                                "dummy", 0, 0, 0, 1, 0, 0);
 
-TEST(NodeAllocation) {
-  GraphTester graph;
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator);
-  CHECK(n2->id() != n1->id());
-}
-
-
-TEST(NodeWithOpcode) {
-  GraphTester graph;
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator);
-  CHECK(n1->op() == &dummy_operator);
-  CHECK(n2->op() == &dummy_operator);
-}
-
-
-TEST(NodeInputs1) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator, n0);
-  CHECK_EQ(1, n2->InputCount());
-  CHECK(n0 == n2->InputAt(0));
-}
-
-
-TEST(NodeInputs2) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
-  CHECK_EQ(2, n2->InputCount());
-  CHECK(n0 == n2->InputAt(0));
-  CHECK(n1 == n2->InputAt(1));
-}
-
-
-TEST(NodeInputs3) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator, n0, n1, n1);
-  CHECK_EQ(3, n2->InputCount());
-  CHECK(n0 == n2->InputAt(0));
-  CHECK(n1 == n2->InputAt(1));
-  CHECK(n1 == n2->InputAt(2));
-}
-
-
-TEST(NodeInputIteratorEmpty) {
-  GraphTester graph;
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node::Inputs::iterator i(n1->inputs().begin());
-  int input_count = 0;
-  for (; i != n1->inputs().end(); ++i) {
-    input_count++;
-  }
-  CHECK_EQ(0, input_count);
-}
-
-
-TEST(NodeInputIteratorOne) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node::Inputs::iterator i(n1->inputs().begin());
-  CHECK_EQ(1, n1->InputCount());
-  CHECK_EQ(n0, *i);
-  ++i;
-  CHECK(n1->inputs().end() == i);
-}
-
-
-TEST(NodeUseIteratorEmpty) {
-  GraphTester graph;
-  Node* n1 = graph.NewNode(&dummy_operator);
-  int use_count = 0;
-  for (Edge const edge : n1->use_edges()) {
-    USE(edge);
-    use_count++;
-  }
-  CHECK_EQ(0, use_count);
-}
-
-
-TEST(NodeUseIteratorOne) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node::Uses::iterator i(n0->uses().begin());
-  CHECK_EQ(n1, *i);
-  ++i;
-  CHECK(n0->uses().end() == i);
-}
-
-
-TEST(NodeUseIteratorReplaceNoUses) {
-  GraphTester graph;
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator);
-  Node* n2 = graph.NewNode(&dummy_operator);
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  n0->ReplaceUses(n1);
-  CHECK(n0->uses().begin() == n0->uses().end());
-  n0->ReplaceUses(n2);
-  CHECK(n0->uses().begin() == n0->uses().end());
-  USE(n3);
-}
-
-
 TEST(NodeUseIteratorReplaceUses) {
   GraphTester graph;
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0);
   Node* n3 = graph.NewNode(&dummy_operator);
-  Node::Uses::iterator i1(n0->uses().begin());
+  auto i1(n0->uses().begin());
   CHECK_EQ(n1, *i1);
   ++i1;
   CHECK_EQ(n2, *i1);
   n0->ReplaceUses(n3);
-  Node::Uses::iterator i2(n3->uses().begin());
+  auto i2(n3->uses().begin());
   CHECK_EQ(n1, *i2);
   ++i2;
   CHECK_EQ(n2, *i2);
-  Node::Inputs::iterator i3(n1->inputs().begin());
+  auto i3(n1->inputs().begin());
   CHECK_EQ(n3, *i3);
   ++i3;
   CHECK(n1->inputs().end() == i3);
-  Node::Inputs::iterator i4(n2->inputs().begin());
+  auto i4(n2->inputs().begin());
   CHECK_EQ(n3, *i4);
   ++i4;
   CHECK(n2->inputs().end() == i4);
@@ -160,14 +50,14 @@ TEST(NodeUseIteratorReplaceUsesSelf) {
 
   n1->ReplaceInput(0, n1);  // Create self-reference.
 
-  Node::Uses::iterator i1(n1->uses().begin());
+  auto i1(n1->uses().begin());
   CHECK_EQ(n1, *i1);
 
   n1->ReplaceUses(n3);
 
   CHECK(n1->uses().begin() == n1->uses().end());
 
-  Node::Uses::iterator i2(n3->uses().begin());
+  auto i2(n3->uses().begin());
   CHECK_EQ(n1, *i2);
   ++i2;
   CHECK(n1->uses().end() == i2);
@@ -180,7 +70,7 @@ TEST(ReplaceInput) {
   Node* n1 = graph.NewNode(&dummy_operator);
   Node* n2 = graph.NewNode(&dummy_operator);
   Node* n3 = graph.NewNode(&dummy_operator, n0, n1, n2);
-  Node::Inputs::iterator i1(n3->inputs().begin());
+  auto i1(n3->inputs().begin());
   CHECK(n0 == *i1);
   CHECK_EQ(n0, n3->InputAt(0));
   ++i1;
@@ -192,26 +82,26 @@ TEST(ReplaceInput) {
   ++i1;
   CHECK(i1 == n3->inputs().end());
 
-  Node::Uses::iterator i2(n1->uses().begin());
+  auto i2(n1->uses().begin());
   CHECK_EQ(n3, *i2);
   ++i2;
   CHECK(i2 == n1->uses().end());
 
   Node* n4 = graph.NewNode(&dummy_operator);
-  Node::Uses::iterator i3(n4->uses().begin());
+  auto i3(n4->uses().begin());
   CHECK(i3 == n4->uses().end());
 
   n3->ReplaceInput(1, n4);
 
-  Node::Uses::iterator i4(n1->uses().begin());
+  auto i4(n1->uses().begin());
   CHECK(i4 == n1->uses().end());
 
-  Node::Uses::iterator i5(n4->uses().begin());
+  auto i5(n4->uses().begin());
   CHECK_EQ(n3, *i5);
   ++i5;
   CHECK(i5 == n4->uses().end());
 
-  Node::Inputs::iterator i6(n3->inputs().begin());
+  auto i6(n3->inputs().begin());
   CHECK(n0 == *i6);
   CHECK_EQ(n0, n3->InputAt(0));
   ++i6;
@@ -321,7 +211,7 @@ TEST(Inputs) {
 
   // Make sure uses have been hooked op correctly.
   Node::Uses uses(n4->uses());
-  Node::Uses::iterator current = uses.begin();
+  auto current = uses.begin();
   CHECK(current != uses.end());
   CHECK(*current == n3);
   ++current;
@@ -450,7 +340,7 @@ TEST(ReplaceUsesFromAppendedInputs) {
   CHECK_EQ(3, n3->UseCount());
 
   Node::Uses uses(n3->uses());
-  Node::Uses::iterator current = uses.begin();
+  auto current = uses.begin();
   CHECK(current != uses.end());
   CHECK(*current == n1);
   ++current;
@@ -464,76 +354,6 @@ TEST(ReplaceUsesFromAppendedInputs) {
 }
 
 
-template <bool result>
-struct FixedPredicate {
-  bool operator()(const Node* node) const { return result; }
-};
-
-
-TEST(ReplaceUsesIfWithFixedPredicate) {
-  GraphTester graph;
-
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n0);
-  Node* n3 = graph.NewNode(&dummy_operator);
-
-  CHECK_EQ(0, n2->UseCount());
-  n2->ReplaceUsesIf(FixedPredicate<true>(), n1);
-  CHECK_EQ(0, n2->UseCount());
-  n2->ReplaceUsesIf(FixedPredicate<false>(), n1);
-  CHECK_EQ(0, n2->UseCount());
-
-  CHECK_EQ(0, n3->UseCount());
-  n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
-  CHECK_EQ(0, n3->UseCount());
-  n3->ReplaceUsesIf(FixedPredicate<false>(), n1);
-  CHECK_EQ(0, n3->UseCount());
-
-  CHECK_EQ(2, n0->UseCount());
-  CHECK_EQ(0, n1->UseCount());
-  n0->ReplaceUsesIf(FixedPredicate<false>(), n1);
-  CHECK_EQ(2, n0->UseCount());
-  CHECK_EQ(0, n1->UseCount());
-  n0->ReplaceUsesIf(FixedPredicate<true>(), n1);
-  CHECK_EQ(0, n0->UseCount());
-  CHECK_EQ(2, n1->UseCount());
-
-  n1->AppendInput(graph.zone(), n1);
-  CHECK_EQ(3, n1->UseCount());
-  n1->AppendInput(graph.zone(), n3);
-  CHECK_EQ(1, n3->UseCount());
-  n3->ReplaceUsesIf(FixedPredicate<true>(), n1);
-  CHECK_EQ(4, n1->UseCount());
-  CHECK_EQ(0, n3->UseCount());
-  n1->ReplaceUsesIf(FixedPredicate<false>(), n3);
-  CHECK_EQ(4, n1->UseCount());
-  CHECK_EQ(0, n3->UseCount());
-}
-
-
-TEST(ReplaceUsesIfWithEqualTo) {
-  GraphTester graph;
-
-  Node* n0 = graph.NewNode(&dummy_operator);
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
-
-  CHECK_EQ(0, n2->UseCount());
-  n2->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n1), n0);
-  CHECK_EQ(0, n2->UseCount());
-
-  CHECK_EQ(2, n0->UseCount());
-  CHECK_EQ(1, n1->UseCount());
-  n1->ReplaceUsesIf(std::bind1st(std::equal_to<Node*>(), n0), n0);
-  CHECK_EQ(2, n0->UseCount());
-  CHECK_EQ(1, n1->UseCount());
-  n0->ReplaceUsesIf(std::bind2nd(std::equal_to<Node*>(), n2), n1);
-  CHECK_EQ(1, n0->UseCount());
-  CHECK_EQ(2, n1->UseCount());
-}
-
-
 TEST(ReplaceInputMultipleUses) {
   GraphTester graph;
 
index 9543258..960ff92 100644 (file)
@@ -105,6 +105,26 @@ Node* TypedGraphTest::Parameter(Type* type, int32_t index) {
   return node;
 }
 
+
+namespace {
+
+const Operator kDummyOperator(0, Operator::kNoProperties, "Dummy", 0, 0, 0, 1,
+                              0, 0);
+
+}  // namespace
+
+
+TEST_F(GraphTest, NewNode) {
+  Node* n0 = graph()->NewNode(&kDummyOperator);
+  Node* n1 = graph()->NewNode(&kDummyOperator);
+  EXPECT_NE(n0, n1);
+  EXPECT_LT(0, n0->id());
+  EXPECT_LT(0, n1->id());
+  EXPECT_NE(n0->id(), n1->id());
+  EXPECT_EQ(&kDummyOperator, n0->op());
+  EXPECT_EQ(&kDummyOperator, n1->op());
+}
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
diff --git a/test/unittests/compiler/node-properties-unittest.cc b/test/unittests/compiler/node-properties-unittest.cc
new file mode 100644 (file)
index 0000000..4b11b55
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2015 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/common-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::IsNull;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef TestWithZone NodePropertiesTest;
+
+
+TEST_F(NodePropertiesTest, FindProjection) {
+  CommonOperatorBuilder common(zone());
+  Node* start = Node::New(zone(), 0, common.Start(1), 0, nullptr, false);
+  Node* proj0 = Node::New(zone(), 1, common.Projection(0), 1, &start, false);
+  Node* proj1 = Node::New(zone(), 2, common.Projection(1), 1, &start, false);
+  EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0));
+  EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1));
+  EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull());
+  EXPECT_THAT(NodeProperties::FindProjection(start, 1234567890), IsNull());
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/compiler/node-unittest.cc b/test/unittests/compiler/node-unittest.cc
new file mode 100644 (file)
index 0000000..f56d7d6
--- /dev/null
@@ -0,0 +1,170 @@
+// Copyright 2015 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/node.h"
+#include "src/compiler/operator.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::ElementsAre;
+using testing::UnorderedElementsAre;
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef TestWithZone NodeTest;
+
+
+namespace {
+
+const IrOpcode::Value kOpcode0 = static_cast<IrOpcode::Value>(0);
+const IrOpcode::Value kOpcode1 = static_cast<IrOpcode::Value>(1);
+const IrOpcode::Value kOpcode2 = static_cast<IrOpcode::Value>(2);
+
+const Operator kOp0(kOpcode0, Operator::kNoProperties, "Op0", 0, 0, 0, 1, 0, 0);
+const Operator kOp1(kOpcode1, Operator::kNoProperties, "Op1", 1, 0, 0, 1, 0, 0);
+const Operator kOp2(kOpcode2, Operator::kNoProperties, "Op2", 2, 0, 0, 1, 0, 0);
+
+}  // namespace
+
+
+TEST_F(NodeTest, New) {
+  Node* const node = Node::New(zone(), 1, &kOp0, 0, nullptr, false);
+  EXPECT_EQ(1, node->id());
+  EXPECT_EQ(0, node->UseCount());
+  EXPECT_TRUE(node->uses().empty());
+  EXPECT_EQ(0, node->InputCount());
+  EXPECT_TRUE(node->inputs().empty());
+  EXPECT_EQ(&kOp0, node->op());
+  EXPECT_EQ(kOpcode0, node->opcode());
+}
+
+
+TEST_F(NodeTest, NewWithInputs) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  EXPECT_EQ(0, n0->UseCount());
+  EXPECT_EQ(0, n0->InputCount());
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  EXPECT_EQ(1, n0->UseCount());
+  EXPECT_EQ(n1, n0->UseAt(0));
+  EXPECT_EQ(0, n1->UseCount());
+  EXPECT_EQ(1, n1->InputCount());
+  EXPECT_EQ(n0, n1->InputAt(0));
+  Node* n0_n1[] = {n0, n1};
+  Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
+  EXPECT_EQ(2, n0->UseCount());
+  EXPECT_EQ(n1, n0->UseAt(0));
+  EXPECT_EQ(n2, n0->UseAt(1));
+  EXPECT_EQ(2, n2->InputCount());
+  EXPECT_EQ(n0, n2->InputAt(0));
+  EXPECT_EQ(n1, n2->InputAt(1));
+}
+
+
+TEST_F(NodeTest, InputIteratorEmpty) {
+  Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  EXPECT_EQ(node->inputs().begin(), node->inputs().end());
+}
+
+
+TEST_F(NodeTest, InputIteratorOne) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  EXPECT_THAT(n1->inputs(), ElementsAre(n0));
+}
+
+
+TEST_F(NodeTest, InputIteratorTwo) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  Node* n0_n1[] = {n0, n1};
+  Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
+  EXPECT_THAT(n2->inputs(), ElementsAre(n0, n1));
+}
+
+
+TEST_F(NodeTest, UseIteratorEmpty) {
+  Node* node = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  EXPECT_EQ(node->uses().begin(), node->uses().end());
+}
+
+
+TEST_F(NodeTest, UseIteratorOne) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  EXPECT_THAT(n0->uses(), ElementsAre(n1));
+}
+
+
+TEST_F(NodeTest, UseIteratorTwo) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  Node* n0_n1[] = {n0, n1};
+  Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
+  EXPECT_THAT(n0->uses(), UnorderedElementsAre(n1, n2));
+}
+
+
+TEST_F(NodeTest, OwnedBy) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  EXPECT_FALSE(n0->OwnedBy(n0));
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  EXPECT_FALSE(n0->OwnedBy(n0));
+  EXPECT_FALSE(n1->OwnedBy(n1));
+  EXPECT_TRUE(n0->OwnedBy(n1));
+  Node* n0_n1[] = {n0, n1};
+  Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
+  EXPECT_FALSE(n0->OwnedBy(n0));
+  EXPECT_FALSE(n1->OwnedBy(n1));
+  EXPECT_FALSE(n2->OwnedBy(n2));
+  EXPECT_FALSE(n0->OwnedBy(n1));
+  EXPECT_FALSE(n0->OwnedBy(n2));
+  EXPECT_TRUE(n1->OwnedBy(n2));
+  n2->ReplaceInput(0, n2);
+  EXPECT_TRUE(n0->OwnedBy(n1));
+  EXPECT_TRUE(n1->OwnedBy(n2));
+  n2->ReplaceInput(1, n0);
+  EXPECT_FALSE(n0->OwnedBy(n1));
+  EXPECT_FALSE(n1->OwnedBy(n2));
+}
+
+
+TEST_F(NodeTest, ReplaceUsesNone) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  Node* n0_n1[] = {n0, n1};
+  Node* n2 = Node::New(zone(), 2, &kOp2, 2, n0_n1, false);
+  Node* node = Node::New(zone(), 42, &kOp0, 0, nullptr, false);
+  EXPECT_TRUE(node->uses().empty());
+  node->ReplaceUses(n0);
+  EXPECT_TRUE(node->uses().empty());
+  node->ReplaceUses(n1);
+  EXPECT_TRUE(node->uses().empty());
+  node->ReplaceUses(n2);
+  EXPECT_TRUE(node->uses().empty());
+}
+
+
+TEST_F(NodeTest, AppendInput) {
+  Node* n0 = Node::New(zone(), 0, &kOp0, 0, nullptr, false);
+  Node* n1 = Node::New(zone(), 1, &kOp1, 1, &n0, false);
+  Node* node = Node::New(zone(), 12345, &kOp0, 0, nullptr, true);
+  EXPECT_TRUE(node->inputs().empty());
+  node->AppendInput(zone(), n0);
+  EXPECT_FALSE(node->inputs().empty());
+  EXPECT_THAT(node->inputs(), ElementsAre(n0));
+  node->AppendInput(zone(), n1);
+  EXPECT_THAT(node->inputs(), ElementsAre(n0, n1));
+  node->AppendInput(zone(), n0);
+  EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0));
+  node->AppendInput(zone(), n0);
+  EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0));
+  node->AppendInput(zone(), n1);
+  EXPECT_THAT(node->inputs(), ElementsAre(n0, n1, n0, n0, n1));
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
index fd47b56..52413be 100644 (file)
         'compiler/machine-operator-unittest.cc',
         'compiler/move-optimizer-unittest.cc',
         'compiler/node-matchers-unittest.cc',
+        'compiler/node-properties-unittest.cc',
         'compiler/node-test-utils.cc',
         'compiler/node-test-utils.h',
+        'compiler/node-unittest.cc',
         'compiler/opcodes-unittest.cc',
         'compiler/register-allocator-unittest.cc',
         'compiler/select-lowering-unittest.cc',
index c9b1eb3..e217654 100644 (file)
         '../../src/compiler/node-marker.h',
         '../../src/compiler/node-matchers.h',
         '../../src/compiler/node-properties-inl.h',
+        '../../src/compiler/node-properties.cc',
         '../../src/compiler/node-properties.h',
         '../../src/compiler/node.cc',
         '../../src/compiler/node.h',