Merge V8 5.3.332.45.  DO NOT MERGE

Test: Manual

FPIIM-449

Change-Id: Id3254828b068abdea3cb10442e0172a8c9a98e03
(cherry picked from commit 13e2dadd00298019ed862f2b2fc5068bba730bcf)
diff --git a/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc b/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc
new file mode 100644
index 0000000..795bee8
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2016 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/v8.h"
+
+#include "src/factory.h"
+#include "src/interpreter/bytecode-label.h"
+#include "src/interpreter/bytecode-register-optimizer.h"
+#include "src/objects-inl.h"
+#include "src/objects.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
+                                      public TestWithIsolateAndZone {
+ public:
+  BytecodeRegisterOptimizerTest() {}
+  ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; }
+
+  void Initialize(int number_of_parameters, int number_of_locals) {
+    register_allocator_ =
+        new TemporaryRegisterAllocator(zone(), number_of_locals);
+    register_optimizer_ = new (zone()) BytecodeRegisterOptimizer(
+        zone(), register_allocator_, number_of_parameters, this);
+  }
+
+  void Write(BytecodeNode* node) override { output_.push_back(*node); }
+  void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
+    output_.push_back(*node);
+  }
+  void BindLabel(BytecodeLabel* label) override {}
+  void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {}
+  Handle<BytecodeArray> ToBytecodeArray(
+      int fixed_register_count, int parameter_count,
+      Handle<FixedArray> handle_table) override {
+    return Handle<BytecodeArray>();
+  }
+
+  TemporaryRegisterAllocator* allocator() { return register_allocator_; }
+  BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; }
+
+  Register NewTemporary() {
+    return Register(allocator()->BorrowTemporaryRegister());
+  }
+
+  void KillTemporary(Register reg) {
+    allocator()->ReturnTemporaryRegister(reg.index());
+  }
+
+  size_t write_count() const { return output_.size(); }
+  const BytecodeNode& last_written() const { return output_.back(); }
+  const std::vector<BytecodeNode>* output() { return &output_; }
+
+ private:
+  TemporaryRegisterAllocator* register_allocator_;
+  BytecodeRegisterOptimizer* register_optimizer_;
+
+  std::vector<BytecodeNode> output_;
+};
+
+// Sanity tests.
+
+TEST_F(BytecodeRegisterOptimizerTest, WriteNop) {
+  Initialize(1, 1);
+  BytecodeNode node(Bytecode::kNop);
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(node, last_written());
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, WriteNopExpression) {
+  Initialize(1, 1);
+  BytecodeNode node(Bytecode::kNop);
+  node.source_info().MakeExpressionPosition(3);
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(node, last_written());
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, WriteNopStatement) {
+  Initialize(1, 1);
+  BytecodeNode node(Bytecode::kNop);
+  node.source_info().MakeStatementPosition(3);
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(node, last_written());
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) {
+  Initialize(1, 1);
+  Register temp = NewTemporary();
+  BytecodeNode node(Bytecode::kStar, temp.ToOperand());
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 0);
+  BytecodeLabel label;
+  BytecodeNode jump(Bytecode::kJump, 0);
+  optimizer()->WriteJump(&jump, &label);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar);
+  CHECK_EQ(output()->at(0).operand(0), temp.ToOperand());
+  CHECK_EQ(output()->at(1).bytecode(), Bytecode::kJump);
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForBind) {
+  Initialize(1, 1);
+  Register temp = NewTemporary();
+  BytecodeNode node(Bytecode::kStar, temp.ToOperand());
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 0);
+  BytecodeLabel label;
+  optimizer()->BindLabel(&label);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar);
+  CHECK_EQ(output()->at(0).operand(0), temp.ToOperand());
+}
+
+// Basic Register Optimizations
+
+TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) {
+  Initialize(3, 1);
+  Register parameter = Register::FromParameterIndex(1, 3);
+  BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand());
+  optimizer()->Write(&node0);
+  CHECK_EQ(write_count(), 0);
+  Register temp = NewTemporary();
+  BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand());
+  optimizer()->Write(&node1);
+  CHECK_EQ(write_count(), 0);
+  KillTemporary(temp);
+  CHECK_EQ(write_count(), 0);
+  BytecodeNode node2(Bytecode::kReturn);
+  optimizer()->Write(&node2);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar);
+  CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand());
+  CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn);
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) {
+  Initialize(3, 1);
+  Register parameter = Register::FromParameterIndex(1, 3);
+  BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand());
+  optimizer()->Write(&node0);
+  CHECK_EQ(write_count(), 0);
+  Register local = Register(0);
+  BytecodeNode node1(Bytecode::kStar, local.ToOperand());
+  optimizer()->Write(&node1);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov);
+  CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand());
+  CHECK_EQ(output()->at(0).operand(1), local.ToOperand());
+
+  BytecodeNode node2(Bytecode::kReturn);
+  optimizer()->Write(&node2);
+  CHECK_EQ(write_count(), 3);
+  CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar);
+  CHECK_EQ(output()->at(1).operand(0), local.ToOperand());
+  CHECK_EQ(output()->at(2).bytecode(), Bytecode::kReturn);
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotMaterializedForInput) {
+  Initialize(3, 1);
+  Register parameter = Register::FromParameterIndex(1, 3);
+  Register temp0 = NewTemporary();
+  Register temp1 = NewTemporary();
+  BytecodeNode node0(Bytecode::kMov, parameter.ToOperand(), temp0.ToOperand());
+  optimizer()->Write(&node0);
+  BytecodeNode node1(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand());
+  optimizer()->Write(&node1);
+  CHECK_EQ(write_count(), 0);
+  BytecodeNode node2(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 1);
+  optimizer()->Write(&node2);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kCallJSRuntime);
+  CHECK_EQ(output()->at(0).operand(0), 0);
+  CHECK_EQ(output()->at(0).operand(1), parameter.ToOperand());
+  CHECK_EQ(output()->at(0).operand(2), 1);
+}
+
+TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) {
+  Initialize(3, 1);
+  Register parameter = Register::FromParameterIndex(1, 3);
+  Register temp0 = NewTemporary();
+  Register temp1 = NewTemporary();
+  BytecodeNode node0(Bytecode::kLdaSmi, 3);
+  optimizer()->Write(&node0);
+  CHECK_EQ(write_count(), 1);
+  BytecodeNode node1(Bytecode::kStar, temp0.ToOperand());
+  optimizer()->Write(&node1);
+  BytecodeNode node2(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand());
+  optimizer()->Write(&node2);
+  CHECK_EQ(write_count(), 1);
+  BytecodeNode node3(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 2);
+  optimizer()->Write(&node3);
+  CHECK_EQ(write_count(), 4);
+
+  CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdaSmi);
+  CHECK_EQ(output()->at(0).operand(0), 3);
+
+  CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar);
+  CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand());
+
+  CHECK_EQ(output()->at(2).bytecode(), Bytecode::kMov);
+  CHECK_EQ(output()->at(2).operand(0), parameter.ToOperand());
+  CHECK_EQ(output()->at(2).operand(1), temp1.ToOperand());
+
+  CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime);
+  CHECK_EQ(output()->at(3).operand(0), 0);
+  CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand());
+  CHECK_EQ(output()->at(3).operand(2), 2);
+}
+
+}  // namespace interpreter
+}  // namespace internal
+}  // namespace v8