Merge V8 5.2.361.47  DO NOT MERGE

https://chromium.googlesource.com/v8/v8/+/5.2.361.47

FPIIM-449

Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc
index 255d836..a569c94 100644
--- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc
+++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc
@@ -22,11 +22,16 @@
 
 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
   BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131);
+  Factory* factory = isolate()->factory();
 
   CHECK_EQ(builder.locals_count(), 131);
   CHECK_EQ(builder.context_count(), 1);
   CHECK_EQ(builder.fixed_register_count(), 132);
 
+  Register reg(0);
+  Register other(reg.index() + 1);
+  Register wide(128);
+
   // Emit argument creation operations.
   builder.CreateArguments(CreateArgumentsType::kMappedArguments)
       .CreateArguments(CreateArgumentsType::kUnmappedArguments)
@@ -34,19 +39,27 @@
 
   // Emit constant loads.
   builder.LoadLiteral(Smi::FromInt(0))
+      .StoreAccumulatorInRegister(reg)
       .LoadLiteral(Smi::FromInt(8))
+      .StoreAccumulatorInRegister(reg)
       .LoadLiteral(Smi::FromInt(10000000))
+      .StoreAccumulatorInRegister(reg)
+      .LoadLiteral(factory->NewStringFromStaticChars("A constant"))
+      .StoreAccumulatorInRegister(reg)
       .LoadUndefined()
+      .StoreAccumulatorInRegister(reg)
       .LoadNull()
+      .StoreAccumulatorInRegister(reg)
       .LoadTheHole()
+      .StoreAccumulatorInRegister(reg)
       .LoadTrue()
-      .LoadFalse();
+      .StoreAccumulatorInRegister(reg)
+      .LoadFalse()
+      .StoreAccumulatorInRegister(wide);
 
-  Register reg(0);
-  Register other(reg.index() + 1);
-  Register wide(128);
-
-  builder.LoadAccumulatorWithRegister(reg)
+  builder.StackCheck(0)
+      .LoadAccumulatorWithRegister(other)
+      .StoreAccumulatorInRegister(reg)
       .LoadNull()
       .StoreAccumulatorInRegister(reg);
 
@@ -55,7 +68,6 @@
   builder.MoveRegister(reg, wide);
 
   // Emit global load / store operations.
-  Factory* factory = isolate()->factory();
   Handle<String> name = factory->NewStringFromStaticChars("var_name");
   builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF)
       .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF)
@@ -126,7 +138,10 @@
   builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB);
 
   // Emit unary operator invocations.
-  builder.LogicalNot().TypeOf();
+  builder
+      .LogicalNot()  // ToBooleanLogicalNot
+      .LogicalNot()  // non-ToBoolean LogicalNot
+      .TypeOf();
 
   // Emit delete
   builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
@@ -208,7 +223,7 @@
       .JumpIfFalse(&start);
 
   // Emit stack check bytecode.
-  builder.StackCheck();
+  builder.StackCheck(0);
 
   // Emit throw and re-throw in it's own basic block so that the rest of the
   // code isn't omitted due to being dead.
@@ -289,6 +304,10 @@
       .BinaryOperation(Token::Value::ADD, reg)
       .JumpIfFalse(&start);
 
+  // Emit generator operations
+  builder.SuspendGenerator(reg)
+      .ResumeGenerator(reg);
+
   // Intrinsics handled by the interpreter.
   builder.CallRuntime(Runtime::kInlineIsArray, reg, 1)
       .CallRuntime(Runtime::kInlineIsArray, wide, 1);
@@ -327,6 +346,9 @@
   // Insert entry for illegal bytecode as this is never willingly emitted.
   scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
 
+  // Insert entry for nop bytecode as this often gets optimized out.
+  scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
+
   // Check return occurs at the end and only once in the BytecodeArray.
   CHECK_EQ(final_bytecode, Bytecode::kReturn);
   CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
@@ -364,14 +386,11 @@
 
 TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
   int index = 1;
-  int32_t operand = -index;
 
   Register the_register(index);
   CHECK_EQ(the_register.index(), index);
 
   int actual_operand = the_register.ToOperand();
-  CHECK_EQ(actual_operand, operand);
-
   int actual_index = Register::FromOperand(actual_operand).index();
   CHECK_EQ(actual_index, index);
 }
@@ -461,7 +480,7 @@
       .BinaryOperation(Token::Value::ADD, reg)
       .JumpIfFalse(&far4);
   for (int i = 0; i < kFarJumpDistance - 18; i++) {
-    builder.LoadUndefined();
+    builder.Debugger();
   }
   builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
   builder.Return();
@@ -502,7 +521,6 @@
   CHECK_EQ(iterator.GetImmediateOperand(0), 2);
   iterator.Advance();
 
-
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
            Smi::FromInt(kFarJumpDistance));
@@ -568,7 +586,7 @@
 
   // Add padding to force wide backwards jumps.
   for (int i = 0; i < 256; i++) {
-    builder.LoadTrue();
+    builder.Debugger();
   }
 
   builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4);
@@ -615,7 +633,7 @@
   }
   // Check padding to force wide backwards jumps.
   for (int i = 0; i < 256; i++) {
-    CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaTrue);
+    CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
     iterator.Advance();
   }
   // Ignore binary operation.
@@ -706,85 +724,6 @@
   CHECK(iterator.done());
 }
 
-TEST_F(BytecodeArrayBuilderTest, OperandScales) {
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(OperandSize::kByte),
-           OperandScale::kSingle);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(OperandSize::kShort),
-           OperandScale::kDouble);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(OperandSize::kQuad),
-           OperandScale::kQuadruple);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(
-               OperandSize::kShort, OperandSize::kShort, OperandSize::kShort,
-               OperandSize::kShort),
-           OperandScale::kDouble);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(
-               OperandSize::kQuad, OperandSize::kShort, OperandSize::kShort,
-               OperandSize::kShort),
-           OperandScale::kQuadruple);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(
-               OperandSize::kShort, OperandSize::kQuad, OperandSize::kShort,
-               OperandSize::kShort),
-           OperandScale::kQuadruple);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(
-               OperandSize::kShort, OperandSize::kShort, OperandSize::kQuad,
-               OperandSize::kShort),
-           OperandScale::kQuadruple);
-  CHECK_EQ(BytecodeArrayBuilder::OperandSizesToScale(
-               OperandSize::kShort, OperandSize::kShort, OperandSize::kShort,
-               OperandSize::kQuad),
-           OperandScale::kQuadruple);
-}
-
-TEST_F(BytecodeArrayBuilderTest, SizesForSignOperands) {
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(0) == OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMaxInt8) ==
-        OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMinInt8) ==
-        OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMaxInt8 + 1) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMinInt8 - 1) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMaxInt16) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMinInt16) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMaxInt16 + 1) ==
-        OperandSize::kQuad);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMinInt16 - 1) ==
-        OperandSize::kQuad);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMaxInt) ==
-        OperandSize::kQuad);
-  CHECK(BytecodeArrayBuilder::SizeForSignedOperand(kMinInt) ==
-        OperandSize::kQuad);
-}
-
-TEST_F(BytecodeArrayBuilderTest, SizesForUnsignOperands) {
-  // int overloads
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(0) == OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(kMaxUInt8) ==
-        OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(kMaxUInt8 + 1) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(kMaxUInt16) ==
-        OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(kMaxUInt16 + 1) ==
-        OperandSize::kQuad);
-  // size_t overloads
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(static_cast<size_t>(0)) ==
-        OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(
-            static_cast<size_t>(kMaxUInt8)) == OperandSize::kByte);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(
-            static_cast<size_t>(kMaxUInt8 + 1)) == OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(
-            static_cast<size_t>(kMaxUInt16)) == OperandSize::kShort);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(
-            static_cast<size_t>(kMaxUInt16 + 1)) == OperandSize::kQuad);
-  CHECK(BytecodeArrayBuilder::SizeForUnsignedOperand(
-            static_cast<size_t>(kMaxUInt32)) == OperandSize::kQuad);
-}
-
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8
diff --git a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
index 43c6caa..aa9effe 100644
--- a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
+++ b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
@@ -37,11 +37,17 @@
   int feedback_slot = 97;
 
   builder.LoadLiteral(heap_num_0)
+      .StoreAccumulatorInRegister(reg_0)
       .LoadLiteral(heap_num_1)
+      .StoreAccumulatorInRegister(reg_0)
       .LoadLiteral(zero)
+      .StoreAccumulatorInRegister(reg_0)
       .LoadLiteral(smi_0)
+      .StoreAccumulatorInRegister(reg_0)
       .LoadLiteral(smi_1)
+      .StoreAccumulatorInRegister(reg_1)
       .LoadAccumulatorWithRegister(reg_0)
+      .StoreAccumulatorInRegister(reg_1)
       .LoadNamedProperty(reg_1, name, feedback_slot)
       .StoreAccumulatorInRegister(param)
       .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, 1, reg_0)
@@ -64,6 +70,15 @@
   offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
@@ -72,6 +87,15 @@
   offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaZero);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
@@ -79,6 +103,15 @@
   offset += Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
@@ -87,6 +120,15 @@
   offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple);
@@ -96,6 +138,15 @@
             kPrefixByteSize;
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdar);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
@@ -104,6 +155,15 @@
   offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kStar);
+  CHECK_EQ(iterator.current_offset(), offset);
+  CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index());
+  CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
+  CHECK(!iterator.done());
+  offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
+  iterator.Advance();
+
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadIC);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
diff --git a/test/unittests/interpreter/bytecode-array-writer-unittest.cc b/test/unittests/interpreter/bytecode-array-writer-unittest.cc
new file mode 100644
index 0000000..a1b4910
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-array-writer-unittest.cc
@@ -0,0 +1,233 @@
+// 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/interpreter/bytecode-array-writer.h"
+#include "src/interpreter/source-position-table.h"
+#include "src/isolate.h"
+#include "src/utils.h"
+#include "test/unittests/interpreter/bytecode-utils.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone {
+ public:
+  BytecodeArrayWriterUnittest()
+      : source_position_builder_(isolate(), zone()),
+        bytecode_array_writer_(zone(), &source_position_builder_) {}
+  ~BytecodeArrayWriterUnittest() override {}
+
+  void Write(BytecodeNode* node, const BytecodeSourceInfo& info);
+  void Write(Bytecode bytecode,
+             const BytecodeSourceInfo& info = BytecodeSourceInfo());
+  void Write(Bytecode bytecode, uint32_t operand0, OperandScale operand_scale,
+             const BytecodeSourceInfo& info = BytecodeSourceInfo());
+  void Write(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
+             OperandScale operand_scale,
+             const BytecodeSourceInfo& info = BytecodeSourceInfo());
+  void Write(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
+             uint32_t operand2, OperandScale operand_scale,
+             const BytecodeSourceInfo& info = BytecodeSourceInfo());
+  void Write(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
+             uint32_t operand2, uint32_t operand3, OperandScale operand_scale,
+             const BytecodeSourceInfo& info = BytecodeSourceInfo());
+
+  SourcePositionTableBuilder* source_position_builder() {
+    return &source_position_builder_;
+  }
+  BytecodeArrayWriter* writer() { return &bytecode_array_writer_; }
+
+ private:
+  SourcePositionTableBuilder source_position_builder_;
+  BytecodeArrayWriter bytecode_array_writer_;
+};
+
+void BytecodeArrayWriterUnittest::Write(BytecodeNode* node,
+                                        const BytecodeSourceInfo& info) {
+  if (info.is_valid()) {
+    node->source_info().Update(info);
+  }
+  writer()->Write(node);
+}
+
+void BytecodeArrayWriterUnittest::Write(Bytecode bytecode,
+                                        const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode);
+  Write(&node, info);
+}
+
+void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
+                                        OperandScale operand_scale,
+                                        const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode, operand0, operand_scale);
+  Write(&node, info);
+}
+
+void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
+                                        uint32_t operand1,
+                                        OperandScale operand_scale,
+                                        const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode, operand0, operand1, operand_scale);
+  Write(&node, info);
+}
+
+void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
+                                        uint32_t operand1, uint32_t operand2,
+                                        OperandScale operand_scale,
+                                        const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode, operand0, operand1, operand2, operand_scale);
+  Write(&node, info);
+}
+
+void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
+                                        uint32_t operand1, uint32_t operand2,
+                                        uint32_t operand3,
+                                        OperandScale operand_scale,
+                                        const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode, operand0, operand1, operand2, operand3,
+                    operand_scale);
+  Write(&node, info);
+}
+
+TEST_F(BytecodeArrayWriterUnittest, SimpleExample) {
+  CHECK_EQ(writer()->bytecodes()->size(), 0);
+
+  Write(Bytecode::kStackCheck, {10, false});
+  CHECK_EQ(writer()->bytecodes()->size(), 1);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0);
+
+  Write(Bytecode::kLdaSmi, 0xff, OperandScale::kSingle, {55, true});
+  CHECK_EQ(writer()->bytecodes()->size(), 3);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0);
+
+  Write(Bytecode::kLdar, Register(1).ToOperand(), OperandScale::kDouble);
+  CHECK_EQ(writer()->bytecodes()->size(), 7);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+
+  Write(Bytecode::kReturn, {70, true});
+  CHECK_EQ(writer()->bytecodes()->size(), 8);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+
+  static const uint8_t bytes[] = {B(StackCheck), B(LdaSmi), U8(0xff), B(Wide),
+                                  B(Ldar),       R16(1),    B(Return)};
+  CHECK_EQ(writer()->bytecodes()->size(), arraysize(bytes));
+  for (size_t i = 0; i < arraysize(bytes); ++i) {
+    CHECK_EQ(writer()->bytecodes()->at(i), bytes[i]);
+  }
+
+  CHECK_EQ(writer()->FlushForOffset(), arraysize(bytes));
+  writer()->FlushBasicBlock();
+  CHECK_EQ(writer()->bytecodes()->size(), arraysize(bytes));
+
+  PositionTableEntry expected_positions[] = {
+      {0, 10, false}, {1, 55, true}, {7, 70, true}};
+  Handle<ByteArray> source_positions =
+      source_position_builder()->ToSourcePositionTable();
+  SourcePositionTableIterator source_iterator(*source_positions);
+  for (size_t i = 0; i < arraysize(expected_positions); ++i) {
+    const PositionTableEntry& expected = expected_positions[i];
+    CHECK_EQ(source_iterator.bytecode_offset(), expected.bytecode_offset);
+    CHECK_EQ(source_iterator.source_position(), expected.source_position);
+    CHECK_EQ(source_iterator.is_statement(), expected.is_statement);
+    source_iterator.Advance();
+  }
+  CHECK(source_iterator.done());
+}
+
+TEST_F(BytecodeArrayWriterUnittest, ComplexExample) {
+  static const uint8_t expected_bytes[] = {
+      // clang-format off
+      /*  0 30 E> */ B(StackCheck),
+      /*  1 42 S> */ B(LdaConstant), U8(0),
+      /*  3 42 E> */ B(Star), R8(1),
+      /*  5 68 S> */ B(JumpIfUndefined), U8(38),
+      /*  7       */ B(JumpIfNull), U8(36),
+      /*  9       */ B(ToObject),
+      /* 10       */ B(Star), R8(3),
+      /* 12       */ B(ForInPrepare), R8(4),
+      /* 14       */ B(LdaZero),
+      /* 15       */ B(Star), R8(7),
+      /* 17 63 S> */ B(ForInDone), R8(7), R8(6),
+      /* 20       */ B(JumpIfTrue), U8(23),
+      /* 22       */ B(ForInNext), R8(3), R8(7), R8(4), U8(1),
+      /* 27       */ B(JumpIfUndefined), U8(10),
+      /* 29       */ B(Star), R8(0),
+      /* 31 54 E> */ B(StackCheck),
+      /* 32       */ B(Ldar), R8(0),
+      /* 34       */ B(Star), R8(2),
+      /* 36 85 S> */ B(Return),
+      /* 37       */ B(ForInStep), R8(7),
+      /* 39       */ B(Star), R8(7),
+      /* 41       */ B(Jump), U8(-24),
+      /* 43       */ B(LdaUndefined),
+      /* 44 85 S> */ B(Return),
+      // clang-format on
+  };
+
+  static const PositionTableEntry expected_positions[] = {
+      {0, 30, false}, {1, 42, true},   {3, 42, false}, {5, 68, true},
+      {17, 63, true}, {31, 54, false}, {36, 85, true}, {44, 85, true}};
+
+#define R(i) static_cast<uint32_t>(Register(i).ToOperand())
+  Write(Bytecode::kStackCheck, {30, false});
+  Write(Bytecode::kLdaConstant, U8(0), OperandScale::kSingle, {42, true});
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0 * kPointerSize);
+  Write(Bytecode::kStar, R(1), OperandScale::kSingle, {42, false});
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+  Write(Bytecode::kJumpIfUndefined, U8(38), OperandScale::kSingle, {68, true});
+  Write(Bytecode::kJumpIfNull, U8(36), OperandScale::kSingle);
+  Write(Bytecode::kToObject);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+  Write(Bytecode::kStar, R(3), OperandScale::kSingle);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 4 * kPointerSize);
+  Write(Bytecode::kForInPrepare, R(4), OperandScale::kSingle);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 7 * kPointerSize);
+  Write(Bytecode::kLdaZero);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 7 * kPointerSize);
+  Write(Bytecode::kStar, R(7), OperandScale::kSingle);
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize);
+  Write(Bytecode::kForInDone, R(7), R(6), OperandScale::kSingle, {63, true});
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize);
+  Write(Bytecode::kJumpIfTrue, U8(23), OperandScale::kSingle);
+  Write(Bytecode::kForInNext, R(3), R(7), R(4), U8(1), OperandScale::kSingle);
+  Write(Bytecode::kJumpIfUndefined, U8(10), OperandScale::kSingle);
+  Write(Bytecode::kStar, R(0), OperandScale::kSingle);
+  Write(Bytecode::kStackCheck, {54, false});
+  Write(Bytecode::kLdar, R(0), OperandScale::kSingle);
+  Write(Bytecode::kStar, R(2), OperandScale::kSingle);
+  Write(Bytecode::kReturn, {85, true});
+  Write(Bytecode::kForInStep, R(7), OperandScale::kSingle);
+  Write(Bytecode::kStar, R(7), OperandScale::kSingle);
+  Write(Bytecode::kJump, U8(-24), OperandScale::kSingle);
+  Write(Bytecode::kLdaUndefined);
+  Write(Bytecode::kReturn, {85, true});
+  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize);
+#undef R
+
+  CHECK_EQ(writer()->bytecodes()->size(), arraysize(expected_bytes));
+  for (size_t i = 0; i < arraysize(expected_bytes); ++i) {
+    CHECK_EQ(static_cast<int>(writer()->bytecodes()->at(i)),
+             static_cast<int>(expected_bytes[i]));
+  }
+
+  Handle<ByteArray> source_positions =
+      source_position_builder()->ToSourcePositionTable();
+  SourcePositionTableIterator source_iterator(*source_positions);
+  for (size_t i = 0; i < arraysize(expected_positions); ++i) {
+    const PositionTableEntry& expected = expected_positions[i];
+    CHECK_EQ(source_iterator.bytecode_offset(), expected.bytecode_offset);
+    CHECK_EQ(source_iterator.source_position(), expected.source_position);
+    CHECK_EQ(source_iterator.is_statement(), expected.is_statement);
+    source_iterator.Advance();
+  }
+  CHECK(source_iterator.done());
+}
+
+}  // namespace interpreter
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc b/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc
new file mode 100644
index 0000000..cf4a920
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc
@@ -0,0 +1,385 @@
+// 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-peephole-optimizer.h"
+#include "src/interpreter/constant-array-builder.h"
+#include "src/objects-inl.h"
+#include "src/objects.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+class BytecodePeepholeOptimizerTest : public BytecodePipelineStage,
+                                      public TestWithIsolateAndZone {
+ public:
+  BytecodePeepholeOptimizerTest()
+      : constant_array_builder_(isolate(), zone()),
+        peephole_optimizer_(&constant_array_builder_, this) {}
+  ~BytecodePeepholeOptimizerTest() override {}
+
+  size_t FlushForOffset() override {
+    flush_for_offset_count_++;
+    return 0;
+  };
+
+  void FlushBasicBlock() override { flush_basic_block_count_++; }
+
+  void Write(BytecodeNode* node) override {
+    write_count_++;
+    last_written_.Clone(node);
+  }
+
+  BytecodePeepholeOptimizer* optimizer() { return &peephole_optimizer_; }
+  ConstantArrayBuilder* constant_array() { return &constant_array_builder_; }
+
+  int flush_for_offset_count() const { return flush_for_offset_count_; }
+  int flush_basic_block_count() const { return flush_basic_block_count_; }
+  int write_count() const { return write_count_; }
+  const BytecodeNode& last_written() const { return last_written_; }
+
+ private:
+  ConstantArrayBuilder constant_array_builder_;
+  BytecodePeepholeOptimizer peephole_optimizer_;
+
+  int flush_for_offset_count_ = 0;
+  int flush_basic_block_count_ = 0;
+  int write_count_ = 0;
+  BytecodeNode last_written_;
+};
+
+// Sanity tests.
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetPassThrough) {
+  CHECK_EQ(flush_for_offset_count(), 0);
+  CHECK_EQ(optimizer()->FlushForOffset(), 0);
+  CHECK_EQ(flush_for_offset_count(), 1);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetRightSize) {
+  BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
+                    OperandScale::kQuadruple);
+  optimizer()->Write(&node);
+  CHECK_EQ(optimizer()->FlushForOffset(), node.Size());
+  CHECK_EQ(flush_for_offset_count(), 1);
+  CHECK_EQ(write_count(), 0);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNop) {
+  BytecodeNode node(Bytecode::kNop);
+  optimizer()->Write(&node);
+  CHECK_EQ(optimizer()->FlushForOffset(), 0);
+  CHECK_EQ(flush_for_offset_count(), 1);
+  CHECK_EQ(write_count(), 0);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopExpression) {
+  BytecodeNode node(Bytecode::kNop);
+  node.source_info().Update({3, false});
+  optimizer()->Write(&node);
+  CHECK_EQ(optimizer()->FlushForOffset(), 0);
+  CHECK_EQ(flush_for_offset_count(), 1);
+  CHECK_EQ(write_count(), 0);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushForOffsetNopStatement) {
+  BytecodeNode node(Bytecode::kNop);
+  node.source_info().Update({3, true});
+  optimizer()->Write(&node);
+  CHECK_EQ(optimizer()->FlushForOffset(), node.Size());
+  CHECK_EQ(flush_for_offset_count(), 1);
+  CHECK_EQ(write_count(), 0);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, FlushBasicBlockPassThrough) {
+  CHECK_EQ(flush_basic_block_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(flush_basic_block_count(), 1);
+  CHECK_EQ(write_count(), 0);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, WriteOneFlushBasicBlock) {
+  BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
+                    OperandScale::kQuadruple);
+  optimizer()->Write(&node);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(node, last_written());
+}
+
+// Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode().
+
+TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) {
+  BytecodeNode first(Bytecode::kLdaNull);
+  BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) {
+  BytecodeNode first(Bytecode::kLdaTrue);
+  BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue);
+  CHECK_EQ(last_written().operand(0), second.operand(0));
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) {
+  BytecodeNode first(Bytecode::kLdaNull);
+  BytecodeNode second(Bytecode::kToBooleanLogicalNot);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) {
+  BytecodeNode first(Bytecode::kLdaTrue);
+  BytecodeNode second(Bytecode::kToBooleanLogicalNot);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot);
+}
+
+// Tests covering BytecodePeepholeOptimizer::CanElideCurrent().
+
+TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRy) {
+  BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand(),
+                      OperandScale::kSingle);
+  optimizer()->Write(&first);
+  optimizer()->FlushForOffset();  // Prevent CanElideLast removing |first|.
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRx) {
+  BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
+                      OperandScale::kSingle);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushForOffset();  // Prevent CanElideLast removing |first|.
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatement) {
+  BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
+                      OperandScale::kSingle);
+  second.source_info().Update({0, true});
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushForOffset();  // Prevent CanElideLast removing |first|.
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kNop);
+  CHECK_EQ(last_written().source_info(), second.source_info());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdarRxLdarRxStatementStarRy) {
+  BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand(),
+                      OperandScale::kSingle);
+  BytecodeNode third(Bytecode::kStar, Register(3).ToOperand(),
+                     OperandScale::kSingle);
+  second.source_info().Update({0, true});
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushForOffset();  // Prevent CanElideLast removing |first|.
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 1);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  // Source position should move |second| to |third| when |second| is elided.
+  third.source_info().Update(second.source_info());
+  CHECK_EQ(last_written(), third);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdarToName) {
+  BytecodeNode first(Bytecode::kLdar, Register(0).ToOperand(),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kToName);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, ToNameToName) {
+  BytecodeNode first(Bytecode::kToName);
+  BytecodeNode second(Bytecode::kToName);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, TypeOfToName) {
+  BytecodeNode first(Bytecode::kTypeOf);
+  BytecodeNode second(Bytecode::kToName);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdaConstantStringToName) {
+  Handle<Object> word =
+      isolate()->factory()->NewStringFromStaticChars("optimizing");
+  size_t index = constant_array()->Insert(word);
+  BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kToName);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdaConstantNumberToName) {
+  Handle<Object> word = isolate()->factory()->NewNumber(0.380);
+  size_t index = constant_array()->Insert(word);
+  BytecodeNode first(Bytecode::kLdaConstant, static_cast<uint32_t>(index),
+                     OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kToName);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+// Tests covering BytecodePeepholeOptimizer::CanElideLast().
+
+TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalseNotDiscardable) {
+  BytecodeNode first(Bytecode::kLdaTrue);
+  BytecodeNode second(Bytecode::kLdaFalse);
+  optimizer()->Write(&first);
+  optimizer()->FlushForOffset();  // Prevent discarding of |first|.
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), first);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdaTrueLdaFalse) {
+  BytecodeNode first(Bytecode::kLdaTrue);
+  BytecodeNode second(Bytecode::kLdaFalse);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) {
+  BytecodeNode first(Bytecode::kLdaTrue);
+  first.source_info().Update({3, false});
+  BytecodeNode second(Bytecode::kLdaFalse);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+  second.source_info().Update(first.source_info());
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) {
+  BytecodeNode first(Bytecode::kNop);
+  BytecodeNode second(Bytecode::kStackCheck);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written(), second);
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) {
+  BytecodeNode first(Bytecode::kNop);
+  first.source_info().Update({3, false});
+  BytecodeNode second(Bytecode::kStackCheck);
+  optimizer()->Write(&first);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 0);
+  optimizer()->FlushBasicBlock();
+  CHECK_EQ(write_count(), 1);
+  second.source_info().Update(first.source_info());
+  CHECK_EQ(last_written(), second);
+}
+
+}  // namespace interpreter
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/interpreter/bytecode-pipeline-unittest.cc b/test/unittests/interpreter/bytecode-pipeline-unittest.cc
new file mode 100644
index 0000000..f12391c
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-pipeline-unittest.cc
@@ -0,0 +1,198 @@
+// 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/interpreter/bytecode-pipeline.h"
+#include "src/interpreter/bytecode-register-allocator.h"
+#include "src/isolate.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+using BytecodeNodeTest = TestWithIsolateAndZone;
+
+TEST(BytecodeSourceInfo, Operations) {
+  BytecodeSourceInfo x(0, true);
+  CHECK_EQ(x.source_position(), 0);
+  CHECK_EQ(x.is_statement(), true);
+  CHECK_EQ(x.is_valid(), true);
+  x.set_invalid();
+  CHECK_EQ(x.is_statement(), false);
+  CHECK_EQ(x.is_valid(), false);
+
+  x.Update({1, true});
+  BytecodeSourceInfo y(1, true);
+  CHECK(x == y);
+  CHECK(!(x != y));
+
+  x.set_invalid();
+  CHECK(!(x == y));
+  CHECK(x != y);
+
+  y.Update({2, false});
+  CHECK_EQ(y.source_position(), 1);
+  CHECK_EQ(y.is_statement(), true);
+
+  y.Update({2, true});
+  CHECK_EQ(y.source_position(), 2);
+  CHECK_EQ(y.is_statement(), true);
+
+  y.set_invalid();
+  y.Update({3, false});
+  CHECK_EQ(y.source_position(), 3);
+  CHECK_EQ(y.is_statement(), false);
+
+  y.Update({3, true});
+  CHECK_EQ(y.source_position(), 3);
+  CHECK_EQ(y.is_statement(), true);
+}
+
+TEST_F(BytecodeNodeTest, Constructor0) {
+  BytecodeNode node;
+  CHECK_EQ(node.bytecode(), Bytecode::kIllegal);
+  CHECK(!node.source_info().is_valid());
+}
+
+TEST_F(BytecodeNodeTest, Constructor1) {
+  BytecodeNode node(Bytecode::kLdaZero);
+  CHECK_EQ(node.bytecode(), Bytecode::kLdaZero);
+  CHECK_EQ(node.operand_count(), 0);
+  CHECK_EQ(node.operand_scale(), OperandScale::kSingle);
+  CHECK(!node.source_info().is_valid());
+  CHECK_EQ(node.Size(), 1);
+}
+
+TEST_F(BytecodeNodeTest, Constructor2) {
+  uint32_t operands[] = {0x11};
+  BytecodeNode node(Bytecode::kJumpIfTrue, operands[0], OperandScale::kDouble);
+  CHECK_EQ(node.bytecode(), Bytecode::kJumpIfTrue);
+  CHECK_EQ(node.operand_count(), 1);
+  CHECK_EQ(node.operand(0), operands[0]);
+  CHECK_EQ(node.operand_scale(), OperandScale::kDouble);
+  CHECK(!node.source_info().is_valid());
+  CHECK_EQ(node.Size(), 4);
+}
+
+TEST_F(BytecodeNodeTest, Constructor3) {
+  uint32_t operands[] = {0x11, 0x22};
+  BytecodeNode node(Bytecode::kLdaGlobal, operands[0], operands[1],
+                    OperandScale::kQuadruple);
+  CHECK_EQ(node.bytecode(), Bytecode::kLdaGlobal);
+  CHECK_EQ(node.operand_count(), 2);
+  CHECK_EQ(node.operand(0), operands[0]);
+  CHECK_EQ(node.operand(1), operands[1]);
+  CHECK_EQ(node.operand_scale(), OperandScale::kQuadruple);
+  CHECK(!node.source_info().is_valid());
+  CHECK_EQ(node.Size(), 10);
+}
+
+TEST_F(BytecodeNodeTest, Constructor4) {
+  uint32_t operands[] = {0x11, 0x22, 0x33};
+  BytecodeNode node(Bytecode::kLoadIC, operands[0], operands[1], operands[2],
+                    OperandScale::kSingle);
+  CHECK_EQ(node.operand_count(), 3);
+  CHECK_EQ(node.bytecode(), Bytecode::kLoadIC);
+  CHECK_EQ(node.operand(0), operands[0]);
+  CHECK_EQ(node.operand(1), operands[1]);
+  CHECK_EQ(node.operand(2), operands[2]);
+  CHECK_EQ(node.operand_scale(), OperandScale::kSingle);
+  CHECK(!node.source_info().is_valid());
+  CHECK_EQ(node.Size(), 4);
+}
+
+TEST_F(BytecodeNodeTest, Constructor5) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  CHECK_EQ(node.operand_count(), 4);
+  CHECK_EQ(node.bytecode(), Bytecode::kForInNext);
+  CHECK_EQ(node.operand(0), operands[0]);
+  CHECK_EQ(node.operand(1), operands[1]);
+  CHECK_EQ(node.operand(2), operands[2]);
+  CHECK_EQ(node.operand(3), operands[3]);
+  CHECK_EQ(node.operand_scale(), OperandScale::kDouble);
+  CHECK(!node.source_info().is_valid());
+  CHECK_EQ(node.Size(), 10);
+}
+
+TEST_F(BytecodeNodeTest, Equality) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  CHECK_EQ(node, node);
+  BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
+                     operands[2], operands[3], OperandScale::kDouble);
+  CHECK_EQ(node, other);
+}
+
+TEST_F(BytecodeNodeTest, EqualityWithSourceInfo) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  node.source_info().Update({3, true});
+  CHECK_EQ(node, node);
+  BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
+                     operands[2], operands[3], OperandScale::kDouble);
+  other.source_info().Update({3, true});
+  CHECK_EQ(node, other);
+}
+
+TEST_F(BytecodeNodeTest, NoEqualityWithDifferentSourceInfo) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  node.source_info().Update({3, true});
+  BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
+                     operands[2], operands[3], OperandScale::kDouble);
+  CHECK_NE(node, other);
+}
+
+TEST_F(BytecodeNodeTest, Clone) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  BytecodeNode clone;
+  clone.Clone(&node);
+  CHECK_EQ(clone, node);
+}
+
+TEST_F(BytecodeNodeTest, SetBytecode0) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  BytecodeSourceInfo source_info(77, false);
+  node.source_info().Update(source_info);
+
+  BytecodeNode clone;
+  clone.Clone(&node);
+  clone.set_bytecode(Bytecode::kNop);
+  CHECK_EQ(clone.bytecode(), Bytecode::kNop);
+  CHECK_EQ(clone.operand_count(), 0);
+  CHECK_EQ(clone.operand_scale(), OperandScale::kSingle);
+  CHECK_EQ(clone.source_info(), source_info);
+}
+
+TEST_F(BytecodeNodeTest, SetBytecode1) {
+  uint32_t operands[] = {0x71, 0xa5, 0x5a, 0xfc};
+  BytecodeNode node(Bytecode::kForInNext, operands[0], operands[1], operands[2],
+                    operands[3], OperandScale::kDouble);
+  BytecodeSourceInfo source_info(77, false);
+  node.source_info().Update(source_info);
+
+  BytecodeNode clone;
+  clone.Clone(&node);
+  clone.set_bytecode(Bytecode::kJump, 0x01aabbcc, OperandScale::kQuadruple);
+  CHECK_EQ(clone.bytecode(), Bytecode::kJump);
+  CHECK_EQ(clone.operand_count(), 1);
+  CHECK_EQ(clone.operand(0), 0x01aabbcc);
+  CHECK_EQ(clone.operand_scale(), OperandScale::kQuadruple);
+  CHECK_EQ(clone.source_info(), source_info);
+}
+
+}  // namespace interpreter
+}  // namespace internal
+}  // namespace v8
diff --git a/test/unittests/interpreter/bytecode-utils.h b/test/unittests/interpreter/bytecode-utils.h
new file mode 100644
index 0000000..fffb719
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-utils.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef V8_UNITTESTS_INTERPRETER_BYTECODE_UTILS_H_
+#define V8_UNITTESTS_INTERPRETER_BYTECODE_UTILS_H_
+
+#include "src/frames.h"
+
+#if V8_TARGET_LITTLE_ENDIAN
+
+#define EXTRACT(x, n) static_cast<uint8_t>((x) >> (8 * n))
+#define U16(i) EXTRACT(i, 0), EXTRACT(i, 1)
+#define U32(i) EXTRACT(i, 0), EXTRACT(i, 1), EXTRACT(i, 2), EXTRACT(i, 3)
+
+#elif V8_TARGET_BIG_ENDIAN
+
+#define EXTRACT(x, n) static_cast<uint8_t>((x) >> (8 * n))
+
+#define U16(i) EXTRACT(i, 1), EXTRACT(i, 0)
+#define U32(i) EXTRACT(i, 3), EXTRACT(i, 2), EXTRACT(i, 1), EXTRACT(i, 0)
+
+#else
+
+#error "Unknown Architecture"
+
+#endif
+
+#define U8(i) static_cast<uint8_t>(i)
+#define B(Name) static_cast<uint8_t>(Bytecode::k##Name)
+#define REG_OPERAND(i) \
+  (InterpreterFrameConstants::kRegisterFileFromFp / kPointerSize - (i))
+#define R8(i) static_cast<uint8_t>(REG_OPERAND(i))
+#define R16(i) U16(REG_OPERAND(i))
+#define R32(i) U32(REG_OPERAND(i))
+
+#endif  // V8_UNITTESTS_INTERPRETER_BYTECODE_UTILS_H_
diff --git a/test/unittests/interpreter/bytecodes-unittest.cc b/test/unittests/interpreter/bytecodes-unittest.cc
index b3554c3..eebacb2 100644
--- a/test/unittests/interpreter/bytecodes-unittest.cc
+++ b/test/unittests/interpreter/bytecodes-unittest.cc
@@ -7,6 +7,7 @@
 #include "src/v8.h"
 
 #include "src/interpreter/bytecodes.h"
+#include "test/unittests/interpreter/bytecode-utils.h"
 #include "test/unittests/test-utils.h"
 
 namespace v8 {
@@ -31,15 +32,6 @@
     Register reg2 = Register::FromOperand(operand2);
     CHECK_EQ(i, reg2.index());
   }
-
-  for (int i = 0; i <= kMaxUInt8; i++) {
-    Register reg = Register::FromOperand(i);
-    if (i > 0) {
-      CHECK(reg.is_parameter());
-    } else {
-      CHECK(!reg.is_parameter());
-    }
-  }
 }
 
 TEST(OperandConversion, Parameters) {
@@ -85,9 +77,13 @@
 }
 
 TEST(OperandScaling, ScalableAndNonScalable) {
-  for (OperandScale operand_scale = OperandScale::kSingle;
-       operand_scale <= OperandScale::kMaxValid;
-       operand_scale = Bytecodes::NextOperandScale(operand_scale)) {
+  const OperandScale kOperandScales[] = {
+#define VALUE(Name, _) OperandScale::k##Name,
+      OPERAND_SCALE_LIST(VALUE)
+#undef VALUE
+  };
+
+  for (OperandScale operand_scale : kOperandScales) {
     int scale = static_cast<int>(operand_scale);
     CHECK_EQ(Bytecodes::Size(Bytecode::kCallRuntime, operand_scale),
              1 + 2 + 2 * scale);
@@ -185,23 +181,22 @@
     const char* output;
   };
 
-#define B(Name) static_cast<uint8_t>(Bytecode::k##Name)
   const BytecodesAndResult cases[] = {
-      {{B(LdaSmi), 0x01}, 2, 0, "            LdaSmi [1]"},
-      {{B(Wide), B(LdaSmi), 0xe8, 0x03}, 4, 0, "      LdaSmi.Wide [1000]"},
-      {{B(ExtraWide), B(LdaSmi), 0xa0, 0x86, 0x01, 0x00},
+      {{B(LdaSmi), U8(1)}, 2, 0, "            LdaSmi [1]"},
+      {{B(Wide), B(LdaSmi), U16(1000)}, 4, 0, "      LdaSmi.Wide [1000]"},
+      {{B(ExtraWide), B(LdaSmi), U32(100000)},
        6,
        0,
        "LdaSmi.ExtraWide [100000]"},
-      {{B(LdaSmi), 0xff}, 2, 0, "            LdaSmi [-1]"},
-      {{B(Wide), B(LdaSmi), 0x18, 0xfc}, 4, 0, "      LdaSmi.Wide [-1000]"},
-      {{B(ExtraWide), B(LdaSmi), 0x60, 0x79, 0xfe, 0xff},
+      {{B(LdaSmi), U8(-1)}, 2, 0, "            LdaSmi [-1]"},
+      {{B(Wide), B(LdaSmi), U16(-1000)}, 4, 0, "      LdaSmi.Wide [-1000]"},
+      {{B(ExtraWide), B(LdaSmi), U32(-100000)},
        6,
        0,
        "LdaSmi.ExtraWide [-100000]"},
-      {{B(Star), 0xfb}, 2, 0, "            Star r5"},
-      {{B(Wide), B(Star), 0x78, 0xff}, 4, 0, "      Star.Wide r136"},
-      {{B(Wide), B(Call), 0x7a, 0xff, 0x79, 0xff, 0x02, 0x00, 0xb1, 0x00},
+      {{B(Star), R8(5)}, 2, 0, "            Star r5"},
+      {{B(Wide), B(Star), R16(136)}, 4, 0, "      Star.Wide r136"},
+      {{B(Wide), B(Call), R16(134), R16(135), U16(2), U16(177)},
        10,
        0,
        "Call.Wide r134, r135, #2, [177]"},
@@ -210,16 +205,15 @@
        2,
        3,
        "            Ldar a1"},
-      {{B(Wide), B(CreateObjectLiteral), 0x01, 0x02, 0x03, 0x04, 0xa5},
+      {{B(Wide), B(CreateObjectLiteral), U16(513), U16(1027), U8(165)},
        7,
        0,
        "CreateObjectLiteral.Wide [513], [1027], #165"},
-      {{B(ExtraWide), B(JumpIfNull), 0x15, 0xcd, 0x5b, 0x07},
+      {{B(ExtraWide), B(JumpIfNull), U32(123456789)},
        6,
        0,
        "JumpIfNull.ExtraWide [123456789]"},
   };
-#undef B
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
     // Generate reference string by prepending formatted bytes.
@@ -260,13 +254,71 @@
   }
 }
 
-TEST(OperandScale, PrefixesScale) {
-  CHECK(Bytecodes::NextOperandScale(OperandScale::kSingle) ==
-        OperandScale::kDouble);
-  CHECK(Bytecodes::NextOperandScale(OperandScale::kDouble) ==
-        OperandScale::kQuadruple);
-  CHECK(Bytecodes::NextOperandScale(OperandScale::kQuadruple) ==
-        OperandScale::kInvalid);
+TEST(Bytecodes, OperandScales) {
+  CHECK_EQ(Bytecodes::OperandSizesToScale(OperandSize::kByte),
+           OperandScale::kSingle);
+  CHECK_EQ(Bytecodes::OperandSizesToScale(OperandSize::kShort),
+           OperandScale::kDouble);
+  CHECK_EQ(Bytecodes::OperandSizesToScale(OperandSize::kQuad),
+           OperandScale::kQuadruple);
+  CHECK_EQ(
+      Bytecodes::OperandSizesToScale(OperandSize::kShort, OperandSize::kShort,
+                                     OperandSize::kShort, OperandSize::kShort),
+      OperandScale::kDouble);
+  CHECK_EQ(
+      Bytecodes::OperandSizesToScale(OperandSize::kQuad, OperandSize::kShort,
+                                     OperandSize::kShort, OperandSize::kShort),
+      OperandScale::kQuadruple);
+  CHECK_EQ(
+      Bytecodes::OperandSizesToScale(OperandSize::kShort, OperandSize::kQuad,
+                                     OperandSize::kShort, OperandSize::kShort),
+      OperandScale::kQuadruple);
+  CHECK_EQ(
+      Bytecodes::OperandSizesToScale(OperandSize::kShort, OperandSize::kShort,
+                                     OperandSize::kQuad, OperandSize::kShort),
+      OperandScale::kQuadruple);
+  CHECK_EQ(
+      Bytecodes::OperandSizesToScale(OperandSize::kShort, OperandSize::kShort,
+                                     OperandSize::kShort, OperandSize::kQuad),
+      OperandScale::kQuadruple);
+}
+
+TEST(Bytecodes, SizesForSignedOperands) {
+  CHECK(Bytecodes::SizeForSignedOperand(0) == OperandSize::kByte);
+  CHECK(Bytecodes::SizeForSignedOperand(kMaxInt8) == OperandSize::kByte);
+  CHECK(Bytecodes::SizeForSignedOperand(kMinInt8) == OperandSize::kByte);
+  CHECK(Bytecodes::SizeForSignedOperand(kMaxInt8 + 1) == OperandSize::kShort);
+  CHECK(Bytecodes::SizeForSignedOperand(kMinInt8 - 1) == OperandSize::kShort);
+  CHECK(Bytecodes::SizeForSignedOperand(kMaxInt16) == OperandSize::kShort);
+  CHECK(Bytecodes::SizeForSignedOperand(kMinInt16) == OperandSize::kShort);
+  CHECK(Bytecodes::SizeForSignedOperand(kMaxInt16 + 1) == OperandSize::kQuad);
+  CHECK(Bytecodes::SizeForSignedOperand(kMinInt16 - 1) == OperandSize::kQuad);
+  CHECK(Bytecodes::SizeForSignedOperand(kMaxInt) == OperandSize::kQuad);
+  CHECK(Bytecodes::SizeForSignedOperand(kMinInt) == OperandSize::kQuad);
+}
+
+TEST(Bytecodes, SizesForUnsignedOperands) {
+  // int overloads
+  CHECK(Bytecodes::SizeForUnsignedOperand(0) == OperandSize::kByte);
+  CHECK(Bytecodes::SizeForUnsignedOperand(kMaxUInt8) == OperandSize::kByte);
+  CHECK(Bytecodes::SizeForUnsignedOperand(kMaxUInt8 + 1) ==
+        OperandSize::kShort);
+  CHECK(Bytecodes::SizeForUnsignedOperand(kMaxUInt16) == OperandSize::kShort);
+  CHECK(Bytecodes::SizeForUnsignedOperand(kMaxUInt16 + 1) ==
+        OperandSize::kQuad);
+  // size_t overloads
+  CHECK(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(0)) ==
+        OperandSize::kByte);
+  CHECK(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt8)) ==
+        OperandSize::kByte);
+  CHECK(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt8 + 1)) ==
+        OperandSize::kShort);
+  CHECK(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt16)) ==
+        OperandSize::kShort);
+  CHECK(Bytecodes::SizeForUnsignedOperand(
+            static_cast<size_t>(kMaxUInt16 + 1)) == OperandSize::kQuad);
+  CHECK(Bytecodes::SizeForUnsignedOperand(static_cast<size_t>(kMaxUInt32)) ==
+        OperandSize::kQuad);
 }
 
 TEST(OperandScale, PrefixesRequired) {
diff --git a/test/unittests/interpreter/interpreter-assembler-unittest.cc b/test/unittests/interpreter/interpreter-assembler-unittest.cc
index 0106c57..cd21f09 100644
--- a/test/unittests/interpreter/interpreter-assembler-unittest.cc
+++ b/test/unittests/interpreter/interpreter-assembler-unittest.cc
@@ -313,12 +313,7 @@
 TARGET_TEST_F(InterpreterAssemblerTest, Dispatch) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
-    m.Dispatch();
-    Graph* graph = m.graph();
-
-    Node* end = graph->end();
-    EXPECT_EQ(1, end->InputCount());
-    Node* tail_call_node = end->InputAt(0);
+    Node* tail_call_node = m.Dispatch();
 
     OperandScale operand_scale = OperandScale::kSingle;
     Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd(
@@ -342,12 +337,10 @@
         IsTailCall(
             _, code_target_matcher,
             IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
-            IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
             next_bytecode_offset_matcher,
             IsParameter(InterpreterDispatchDescriptor::kBytecodeArrayParameter),
             IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
-            IsParameter(InterpreterDispatchDescriptor::kContextParameter), _,
-            _));
+            _, _));
   }
 }
 
@@ -359,11 +352,7 @@
   TRACED_FOREACH(int, jump_offset, jump_offsets) {
     TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
       InterpreterAssemblerForTest m(this, bytecode);
-      m.Jump(m.IntPtrConstant(jump_offset));
-      Graph* graph = m.graph();
-      Node* end = graph->end();
-      EXPECT_EQ(1, end->InputCount());
-      Node* tail_call_node = end->InputAt(0);
+      Node* tail_call_node = m.Jump(m.IntPtrConstant(jump_offset));
 
       Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd(
           IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
@@ -385,100 +374,14 @@
           IsTailCall(
               _, code_target_matcher,
               IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
-              IsParameter(
-                  InterpreterDispatchDescriptor::kRegisterFileParameter),
               next_bytecode_offset_matcher, _,
               IsParameter(
                   InterpreterDispatchDescriptor::kDispatchTableParameter),
-              IsParameter(InterpreterDispatchDescriptor::kContextParameter), _,
-              _));
+              _, _));
     }
   }
 }
 
-TARGET_TEST_F(InterpreterAssemblerTest, JumpIfWordEqual) {
-  static const int kJumpIfTrueOffset = 73;
-
-  // If debug code is enabled we emit extra code in Jump.
-  if (FLAG_debug_code) return;
-
-  MachineOperatorBuilder machine(zone());
-
-  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
-    InterpreterAssemblerForTest m(this, bytecode);
-    Node* lhs = m.IntPtrConstant(0);
-    Node* rhs = m.IntPtrConstant(1);
-    m.JumpIfWordEqual(lhs, rhs, m.IntPtrConstant(kJumpIfTrueOffset));
-    Graph* graph = m.graph();
-    Node* end = graph->end();
-    EXPECT_EQ(2, end->InputCount());
-
-    OperandScale operand_scale = OperandScale::kSingle;
-    int jump_offsets[] = {kJumpIfTrueOffset, interpreter::Bytecodes::Size(
-                                                 bytecode, operand_scale)};
-    for (int i = 0; i < static_cast<int>(arraysize(jump_offsets)); i++) {
-      Matcher<Node*> next_bytecode_offset_matcher = IsIntPtrAdd(
-          IsParameter(InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
-          IsIntPtrConstant(jump_offsets[i]));
-      Matcher<Node*> target_bytecode_matcher =
-          m.IsLoad(MachineType::Uint8(), _, next_bytecode_offset_matcher);
-      if (kPointerSize == 8) {
-        target_bytecode_matcher =
-            IsChangeUint32ToUint64(target_bytecode_matcher);
-      }
-      Matcher<Node*> code_target_matcher = m.IsLoad(
-          MachineType::Pointer(),
-          IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
-          IsWordShl(target_bytecode_matcher,
-                    IsIntPtrConstant(kPointerSizeLog2)));
-      EXPECT_THAT(
-          end->InputAt(i),
-          IsTailCall(
-              _, code_target_matcher,
-              IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
-              IsParameter(
-                  InterpreterDispatchDescriptor::kRegisterFileParameter),
-              next_bytecode_offset_matcher, _,
-              IsParameter(
-                  InterpreterDispatchDescriptor::kDispatchTableParameter),
-              IsParameter(InterpreterDispatchDescriptor::kContextParameter), _,
-              _));
-    }
-
-    // TODO(oth): test control flow paths.
-  }
-}
-
-TARGET_TEST_F(InterpreterAssemblerTest, InterpreterReturn) {
-  // If debug code is enabled we emit extra code in InterpreterReturn.
-  if (FLAG_debug_code) return;
-
-  TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
-    InterpreterAssemblerForTest m(this, bytecode);
-    m.InterpreterReturn();
-    Graph* graph = m.graph();
-
-    Node* end = graph->end();
-    EXPECT_EQ(1, end->InputCount());
-    Node* tail_call_node = end->InputAt(0);
-
-    Handle<HeapObject> exit_trampoline =
-        isolate()->builtins()->InterpreterExitTrampoline();
-    EXPECT_THAT(
-        tail_call_node,
-        IsTailCall(
-            _, IsHeapConstant(exit_trampoline),
-            IsParameter(InterpreterDispatchDescriptor::kAccumulatorParameter),
-            IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
-            IsParameter(
-                InterpreterDispatchDescriptor::kBytecodeOffsetParameter),
-            _,
-            IsParameter(InterpreterDispatchDescriptor::kDispatchTableParameter),
-            IsParameter(InterpreterDispatchDescriptor::kContextParameter), _,
-            _));
-  }
-}
-
 TARGET_TEST_F(InterpreterAssemblerTest, BytecodeOperand) {
   static const OperandScale kOperandScales[] = {
       OperandScale::kSingle, OperandScale::kDouble, OperandScale::kQuadruple};
@@ -555,24 +458,21 @@
     EXPECT_THAT(m.GetAccumulator(), accumulator_value_2);
 
     // Should be passed to next bytecode handler on dispatch.
-    m.Dispatch();
-    Graph* graph = m.graph();
-
-    Node* end = graph->end();
-    EXPECT_EQ(1, end->InputCount());
-    Node* tail_call_node = end->InputAt(0);
+    Node* tail_call_node = m.Dispatch();
 
     EXPECT_THAT(tail_call_node,
-                IsTailCall(_, _, accumulator_value_2, _, _, _, _, _, _));
+                IsTailCall(_, _, accumulator_value_2, _, _, _, _));
   }
 }
 
-TARGET_TEST_F(InterpreterAssemblerTest, GetSetContext) {
+TARGET_TEST_F(InterpreterAssemblerTest, GetContext) {
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
-    Node* context_node = m.Int32Constant(100);
-    m.SetContext(context_node);
-    EXPECT_THAT(m.GetContext(), context_node);
+    EXPECT_THAT(
+        m.GetContext(),
+        m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
+                 IsIntPtrConstant(Register::current_context().ToOperand()
+                                  << kPointerSizeLog2)));
   }
 }
 
@@ -581,11 +481,10 @@
     InterpreterAssemblerForTest m(this, bytecode);
     Node* reg_index_node = m.IntPtrConstant(44);
     Node* reg_location_node = m.RegisterLocation(reg_index_node);
-    EXPECT_THAT(
-        reg_location_node,
-        IsIntPtrAdd(
-            IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
-            IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2))));
+    EXPECT_THAT(reg_location_node,
+                IsIntPtrAdd(IsLoadParentFramePointer(),
+                            IsWordShl(reg_index_node,
+                                      IsIntPtrConstant(kPointerSizeLog2))));
   }
 }
 
@@ -594,12 +493,10 @@
     InterpreterAssemblerForTest m(this, bytecode);
     Node* reg_index_node = m.IntPtrConstant(44);
     Node* load_reg_node = m.LoadRegister(reg_index_node);
-    EXPECT_THAT(
-        load_reg_node,
-        m.IsLoad(
-            MachineType::AnyTagged(),
-            IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
-            IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2))));
+    EXPECT_THAT(load_reg_node,
+                m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
+                         IsWordShl(reg_index_node,
+                                   IsIntPtrConstant(kPointerSizeLog2))));
   }
 }
 
@@ -611,12 +508,11 @@
     Node* store_reg_node = m.StoreRegister(store_value, reg_index_node);
     EXPECT_THAT(
         store_reg_node,
-        m.IsStore(
-            StoreRepresentation(MachineRepresentation::kTagged,
-                                kNoWriteBarrier),
-            IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
-            IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2)),
-            store_value));
+        m.IsStore(StoreRepresentation(MachineRepresentation::kTagged,
+                                      kNoWriteBarrier),
+                  IsLoadParentFramePointer(),
+                  IsWordShl(reg_index_node, IsIntPtrConstant(kPointerSizeLog2)),
+                  store_value));
   }
 }
 
@@ -624,9 +520,9 @@
   TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) {
     InterpreterAssemblerForTest m(this, bytecode);
     Node* value = m.Int32Constant(44);
-    EXPECT_THAT(
-        m.SmiTag(value),
-        IsWordShl(value, IsIntPtrConstant(kSmiShiftSize + kSmiTagSize)));
+    EXPECT_THAT(m.SmiTag(value),
+                IsIntPtrConstant(static_cast<intptr_t>(44)
+                                 << (kSmiShiftSize + kSmiTagSize)));
     EXPECT_THAT(
         m.SmiUntag(value),
         IsWordSar(value, IsIntPtrConstant(kSmiShiftSize + kSmiTagSize)));
@@ -730,14 +626,10 @@
     InterpreterAssemblerForTest m(this, bytecode);
     Node* arg1 = m.Int32Constant(2);
     Node* arg2 = m.Int32Constant(3);
-    Node* context =
-        m.Parameter(InterpreterDispatchDescriptor::kContextParameter);
+    Node* context = m.Int32Constant(4);
     Node* call_runtime = m.CallRuntime(Runtime::kAdd, context, arg1, arg2);
-    EXPECT_THAT(
-        call_runtime,
-        IsCall(_, _, arg1, arg2, _, IsInt32Constant(2),
-               IsParameter(InterpreterDispatchDescriptor::kContextParameter), _,
-               _));
+    EXPECT_THAT(call_runtime,
+                IsCall(_, _, arg1, arg2, _, IsInt32Constant(2), context, _, _));
   }
 }
 
@@ -751,8 +643,7 @@
       Node* function_id = m.Int32Constant(0);
       Node* first_arg = m.Int32Constant(1);
       Node* arg_count = m.Int32Constant(2);
-      Node* context =
-          m.Parameter(InterpreterDispatchDescriptor::kContextParameter);
+      Node* context = m.Int32Constant(4);
 
       Matcher<Node*> function_table = IsExternalConstant(
           ExternalReference::runtime_function_table_address(isolate()));
@@ -765,12 +656,9 @@
 
       Node* call_runtime = m.CallRuntimeN(function_id, context, first_arg,
                                           arg_count, result_size);
-      EXPECT_THAT(
-          call_runtime,
-          IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg,
-                 function_entry,
-                 IsParameter(InterpreterDispatchDescriptor::kContextParameter),
-                 _, _));
+      EXPECT_THAT(call_runtime,
+                  IsCall(_, IsHeapConstant(builtin.code()), arg_count,
+                         first_arg, function_entry, context, _, _));
     }
   }
 }
@@ -786,16 +674,11 @@
       Node* function = m.Int32Constant(0);
       Node* first_arg = m.Int32Constant(1);
       Node* arg_count = m.Int32Constant(2);
-      Node* context =
-          m.Parameter(InterpreterDispatchDescriptor::kContextParameter);
+      Node* context = m.Int32Constant(3);
       Node* call_js =
           m.CallJS(function, context, first_arg, arg_count, tail_call_mode);
-      EXPECT_THAT(
-          call_js,
-          IsCall(_, IsHeapConstant(builtin.code()), arg_count, first_arg,
-                 function,
-                 IsParameter(InterpreterDispatchDescriptor::kContextParameter),
-                 _, _));
+      EXPECT_THAT(call_js, IsCall(_, IsHeapConstant(builtin.code()), arg_count,
+                                  first_arg, function, context, _, _));
     }
   }
 }
@@ -805,11 +688,10 @@
     InterpreterAssemblerForTest m(this, bytecode);
     Node* feedback_vector = m.LoadTypeFeedbackVector();
 
-    Matcher<Node*> load_function_matcher = m.IsLoad(
-        MachineType::AnyTagged(),
-        IsParameter(InterpreterDispatchDescriptor::kRegisterFileParameter),
-        IsIntPtrConstant(
-            InterpreterFrameConstants::kFunctionFromRegisterPointer));
+    Matcher<Node*> load_function_matcher =
+        m.IsLoad(MachineType::AnyTagged(), IsLoadParentFramePointer(),
+                 IsIntPtrConstant(Register::function_closure().ToOperand()
+                                  << kPointerSizeLog2));
     Matcher<Node*> load_shared_function_info_matcher =
         m.IsLoad(MachineType::AnyTagged(), load_function_matcher,
                  IsIntPtrConstant(JSFunction::kSharedFunctionInfoOffset -
diff --git a/test/unittests/interpreter/source-position-table-unittest.cc b/test/unittests/interpreter/source-position-table-unittest.cc
index d62302a..230e57d 100644
--- a/test/unittests/interpreter/source-position-table-unittest.cc
+++ b/test/unittests/interpreter/source-position-table-unittest.cc
@@ -25,7 +25,7 @@
 TEST_F(SourcePositionTableTest, EncodeStatement) {
   SourcePositionTableBuilder builder(isolate(), zone());
   for (int i = 0; i < arraysize(offsets); i++) {
-    builder.AddStatementPosition(offsets[i], offsets[i]);
+    builder.AddPosition(offsets[i], offsets[i], true);
   }
 
   // To test correctness, we rely on the assertions in ToSourcePositionTable().
@@ -36,8 +36,8 @@
 TEST_F(SourcePositionTableTest, EncodeStatementDuplicates) {
   SourcePositionTableBuilder builder(isolate(), zone());
   for (int i = 0; i < arraysize(offsets); i++) {
-    builder.AddStatementPosition(offsets[i], offsets[i]);
-    builder.AddStatementPosition(offsets[i], offsets[i] + 1);
+    builder.AddPosition(offsets[i], offsets[i], true);
+    builder.AddPosition(offsets[i], offsets[i] + 1, true);
   }
 
   // To test correctness, we rely on the assertions in ToSourcePositionTable().
@@ -48,7 +48,7 @@
 TEST_F(SourcePositionTableTest, EncodeExpression) {
   SourcePositionTableBuilder builder(isolate(), zone());
   for (int i = 0; i < arraysize(offsets); i++) {
-    builder.AddExpressionPosition(offsets[i], offsets[i]);
+    builder.AddPosition(offsets[i], offsets[i], false);
   }
   CHECK(!builder.ToSourcePositionTable().is_null());
 }
@@ -60,9 +60,9 @@
   for (int i = 0; i < arraysize(offsets); i++) {
     accumulator += offsets[i];
     if (i % 2) {
-      builder.AddStatementPosition(accumulator, accumulator);
+      builder.AddPosition(accumulator, accumulator, true);
     } else {
-      builder.AddExpressionPosition(accumulator, accumulator);
+      builder.AddPosition(accumulator, accumulator, false);
     }
   }
 
@@ -70,9 +70,9 @@
   for (int i = 0; i < arraysize(offsets); i++) {
     accumulator -= offsets[i];
     if (i % 2) {
-      builder.AddStatementPosition(accumulator, accumulator);
+      builder.AddPosition(accumulator, accumulator, true);
     } else {
-      builder.AddExpressionPosition(accumulator, accumulator);
+      builder.AddPosition(accumulator, accumulator, false);
     }
   }