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-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc
index a569c94..7bbef45 100644
--- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc
+++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc
@@ -6,6 +6,7 @@
 
 #include "src/interpreter/bytecode-array-builder.h"
 #include "src/interpreter/bytecode-array-iterator.h"
+#include "src/interpreter/bytecode-label.h"
 #include "src/interpreter/bytecode-register-allocator.h"
 #include "test/unittests/test-utils.h"
 
@@ -47,7 +48,7 @@
       .LoadLiteral(factory->NewStringFromStaticChars("A constant"))
       .StoreAccumulatorInRegister(reg)
       .LoadUndefined()
-      .StoreAccumulatorInRegister(reg)
+      .Debugger()  // Prevent peephole optimization LdaNull, Star -> LdrNull.
       .LoadNull()
       .StoreAccumulatorInRegister(reg)
       .LoadTheHole()
@@ -57,11 +58,12 @@
       .LoadFalse()
       .StoreAccumulatorInRegister(wide);
 
+  // Emit Ldar and Star taking care to foil the register optimizer.
   builder.StackCheck(0)
       .LoadAccumulatorWithRegister(other)
+      .BinaryOperation(Token::ADD, reg)
       .StoreAccumulatorInRegister(reg)
-      .LoadNull()
-      .StoreAccumulatorInRegister(reg);
+      .LoadNull();
 
   // Emit register-register transfer.
   builder.MoveRegister(reg, other);
@@ -69,8 +71,8 @@
 
   // Emit global load / store operations.
   Handle<String> name = factory->NewStringFromStaticChars("var_name");
-  builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF)
-      .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF)
+  builder.LoadGlobal(1, TypeofMode::NOT_INSIDE_TYPEOF)
+      .LoadGlobal(1, TypeofMode::INSIDE_TYPEOF)
       .StoreGlobal(name, 1, LanguageMode::SLOPPY)
       .StoreGlobal(name, 1, LanguageMode::STRICT);
 
@@ -169,26 +171,34 @@
   // Emit control flow. Return must be the last instruction.
   BytecodeLabel start;
   builder.Bind(&start);
-  // Short jumps with Imm8 operands
-  builder.Jump(&start)
-      .JumpIfNull(&start)
-      .JumpIfUndefined(&start)
-      .JumpIfNotHole(&start);
+  {
+    // Short jumps with Imm8 operands
+    BytecodeLabel after_jump;
+    builder.Jump(&start)
+        .Bind(&after_jump)
+        .JumpIfNull(&start)
+        .JumpIfUndefined(&start)
+        .JumpIfNotHole(&start);
+  }
 
   // Longer jumps with constant operands
   BytecodeLabel end[8];
-  builder.Jump(&end[0])
-      .LoadTrue()
-      .JumpIfTrue(&end[1])
-      .LoadTrue()
-      .JumpIfFalse(&end[2])
-      .LoadLiteral(Smi::FromInt(0))
-      .JumpIfTrue(&end[3])
-      .LoadLiteral(Smi::FromInt(0))
-      .JumpIfFalse(&end[4])
-      .JumpIfNull(&end[5])
-      .JumpIfUndefined(&end[6])
-      .JumpIfNotHole(&end[7]);
+  {
+    BytecodeLabel after_jump;
+    builder.Jump(&end[0])
+        .Bind(&after_jump)
+        .LoadTrue()
+        .JumpIfTrue(&end[1])
+        .LoadTrue()
+        .JumpIfFalse(&end[2])
+        .LoadLiteral(Smi::FromInt(0))
+        .JumpIfTrue(&end[3])
+        .LoadLiteral(Smi::FromInt(0))
+        .JumpIfFalse(&end[4])
+        .JumpIfNull(&end[5])
+        .JumpIfUndefined(&end[6])
+        .JumpIfNotHole(&end[7]);
+  }
 
   // Perform an operation that returns boolean value to
   // generate JumpIfTrue/False
@@ -207,20 +217,26 @@
     builder.LoadTrue();
   }
   // Longer jumps requiring Constant operand
-  builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
-      &start);
-  // Perform an operation that returns boolean value to
-  // generate JumpIfTrue/False
-  builder.CompareOperation(Token::Value::EQ, reg)
-      .JumpIfTrue(&start)
-      .CompareOperation(Token::Value::EQ, reg)
-      .JumpIfFalse(&start);
-  // Perform an operation that returns a non-boolean operation to
-  // generate JumpIfToBooleanTrue/False.
-  builder.BinaryOperation(Token::Value::ADD, reg)
-      .JumpIfTrue(&start)
-      .BinaryOperation(Token::Value::ADD, reg)
-      .JumpIfFalse(&start);
+  {
+    BytecodeLabel after_jump;
+    builder.Jump(&start)
+        .Bind(&after_jump)
+        .JumpIfNull(&start)
+        .JumpIfUndefined(&start)
+        .JumpIfNotHole(&start);
+    // Perform an operation that returns boolean value to
+    // generate JumpIfTrue/False
+    builder.CompareOperation(Token::Value::EQ, reg)
+        .JumpIfTrue(&start)
+        .CompareOperation(Token::Value::EQ, reg)
+        .JumpIfFalse(&start);
+    // Perform an operation that returns a non-boolean operation to
+    // generate JumpIfToBooleanTrue/False.
+    builder.BinaryOperation(Token::Value::ADD, reg)
+        .JumpIfTrue(&start)
+        .BinaryOperation(Token::Value::ADD, reg)
+        .JumpIfFalse(&start);
+  }
 
   // Emit stack check bytecode.
   builder.StackCheck(0);
@@ -228,9 +244,9 @@
   // 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.
   BytecodeLabel after_throw;
-  builder.Jump(&after_throw).Throw().Bind(&after_throw);
+  builder.Throw().Bind(&after_throw);
   BytecodeLabel after_rethrow;
-  builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow);
+  builder.ReThrow().Bind(&after_rethrow);
 
   builder.ForInPrepare(reg)
       .ForInDone(reg, reg)
@@ -250,14 +266,14 @@
   Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
 
   // Emit wide global load / store operations.
-  builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF)
-      .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
-      .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
+  builder.LoadGlobal(1024, TypeofMode::NOT_INSIDE_TYPEOF)
+      .LoadGlobal(1024, TypeofMode::INSIDE_TYPEOF)
+      .LoadGlobal(1024, TypeofMode::INSIDE_TYPEOF)
       .StoreGlobal(name, 1024, LanguageMode::SLOPPY)
       .StoreGlobal(wide_name, 1, LanguageMode::STRICT);
 
   // Emit extra wide global load.
-  builder.LoadGlobal(name, 1024 * 1024, TypeofMode::NOT_INSIDE_TYPEOF);
+  builder.LoadGlobal(1024 * 1024, TypeofMode::NOT_INSIDE_TYPEOF);
 
   // Emit wide load / store property operations.
   builder.LoadNamedProperty(reg, wide_name, 0)
@@ -276,6 +292,19 @@
       .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
       .StoreLookupSlot(wide_name, LanguageMode::STRICT);
 
+  // Emit loads which will be transformed to Ldr equivalents by the peephole
+  // optimizer.
+  builder.LoadNamedProperty(reg, name, 0)
+      .StoreAccumulatorInRegister(reg)
+      .LoadKeyedProperty(reg, 0)
+      .StoreAccumulatorInRegister(reg)
+      .LoadContextSlot(reg, 1)
+      .StoreAccumulatorInRegister(reg)
+      .LoadGlobal(0, TypeofMode::NOT_INSIDE_TYPEOF)
+      .StoreAccumulatorInRegister(reg)
+      .LoadUndefined()
+      .StoreAccumulatorInRegister(reg);
+
   // CreateClosureWide
   Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
       factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
@@ -289,14 +318,22 @@
       .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
 
   // Longer jumps requiring ConstantWide operand
-  builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
-      &start);
+  {
+    BytecodeLabel after_jump;
+    builder.Jump(&start)
+        .Bind(&after_jump)
+        .JumpIfNull(&start)
+        .JumpIfUndefined(&start)
+        .JumpIfNotHole(&start);
+  }
+
   // Perform an operation that returns boolean value to
   // generate JumpIfTrue/False
   builder.CompareOperation(Token::Value::EQ, reg)
       .JumpIfTrue(&start)
       .CompareOperation(Token::Value::EQ, reg)
       .JumpIfFalse(&start);
+
   // Perform an operation that returns a non-boolean operation to
   // generate JumpIfToBooleanTrue/False.
   builder.BinaryOperation(Token::Value::ADD, reg)
@@ -349,6 +386,21 @@
   // Insert entry for nop bytecode as this often gets optimized out.
   scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
 
+  if (!FLAG_ignition_peephole) {
+    // Insert entries for bytecodes only emitted by peephole optimizer.
+    scorecard[Bytecodes::ToByte(Bytecode::kLdrNamedProperty)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kLdrKeyedProperty)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kLdrGlobal)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kLdrContextSlot)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kLdrUndefined)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kLogicalNot)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kJump)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrue)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalse)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrueConstant)] = 1;
+    scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalseConstant)] = 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);
@@ -370,9 +422,20 @@
         BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals);
         BytecodeRegisterAllocator temporaries(
             zone(), builder.temporary_register_allocator());
+        for (int i = 0; i < locals + contexts; i++) {
+          builder.LoadLiteral(Smi::FromInt(0));
+          builder.StoreAccumulatorInRegister(Register(i));
+        }
         for (int i = 0; i < temps; i++) {
+          builder.LoadLiteral(Smi::FromInt(0));
           builder.StoreAccumulatorInRegister(temporaries.NewRegister());
         }
+        if (temps > 0) {
+          // Ensure temporaries are used so not optimized away by the
+          // register optimizer.
+          builder.New(Register(locals + contexts), Register(locals + contexts),
+                      static_cast<size_t>(temps));
+        }
         builder.Return();
 
         Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
@@ -398,6 +461,7 @@
 
 TEST_F(BytecodeArrayBuilderTest, Parameters) {
   BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0);
+
   Register param0(builder.Parameter(0));
   Register param9(builder.Parameter(9));
   CHECK_EQ(param9.index() - param0.index(), 9);
@@ -429,6 +493,7 @@
 
 TEST_F(BytecodeArrayBuilderTest, Constants) {
   BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
+
   Factory* factory = isolate()->factory();
   Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
   Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
@@ -447,16 +512,24 @@
   CHECK_EQ(array->constant_pool()->length(), 3);
 }
 
+static Bytecode PeepholeToBoolean(Bytecode jump_bytecode) {
+  return FLAG_ignition_peephole
+             ? Bytecodes::GetJumpWithoutToBoolean(jump_bytecode)
+             : jump_bytecode;
+}
 
 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
   static const int kFarJumpDistance = 256;
 
   BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
+
   Register reg(0);
   BytecodeLabel far0, far1, far2, far3, far4;
   BytecodeLabel near0, near1, near2, near3, near4;
+  BytecodeLabel after_jump0, after_jump1;
 
   builder.Jump(&near0)
+      .Bind(&after_jump0)
       .CompareOperation(Token::Value::EQ, reg)
       .JumpIfTrue(&near1)
       .CompareOperation(Token::Value::EQ, reg)
@@ -471,6 +544,7 @@
       .Bind(&near3)
       .Bind(&near4)
       .Jump(&far0)
+      .Bind(&after_jump1)
       .CompareOperation(Token::Value::EQ, reg)
       .JumpIfTrue(&far1)
       .CompareOperation(Token::Value::EQ, reg)
@@ -496,14 +570,16 @@
   // Ignore compare operation.
   iterator.Advance();
 
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
   CHECK_EQ(iterator.GetImmediateOperand(0), 14);
   iterator.Advance();
 
   // Ignore compare operation.
   iterator.Advance();
 
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
   CHECK_EQ(iterator.GetImmediateOperand(0), 10);
   iterator.Advance();
 
@@ -529,7 +605,8 @@
   // Ignore compare operation.
   iterator.Advance();
 
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrueConstant));
   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
            Smi::FromInt(kFarJumpDistance - 4));
   iterator.Advance();
@@ -537,7 +614,8 @@
   // Ignore compare operation.
   iterator.Advance();
 
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalseConstant));
   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
            Smi::FromInt(kFarJumpDistance - 8));
   iterator.Advance();
@@ -563,6 +641,7 @@
 
 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
   BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
+
   Register reg(0);
 
   BytecodeLabel label0, label1, label2, label3, label4;
@@ -581,7 +660,8 @@
       .BinaryOperation(Token::Value::ADD, reg)
       .JumpIfFalse(&label4);
   for (int i = 0; i < 63; i++) {
-    builder.Jump(&label4);
+    BytecodeLabel after_jump;
+    builder.Jump(&label4).Bind(&after_jump);
   }
 
   // Add padding to force wide backwards jumps.
@@ -594,6 +674,8 @@
   builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2);
   builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1);
   builder.Jump(&label0);
+  BytecodeLabel end;
+  builder.Bind(&end);
   builder.Return();
 
   Handle<BytecodeArray> array = builder.ToBytecodeArray();
@@ -603,13 +685,15 @@
   iterator.Advance();
   // Ignore compare operation.
   iterator.Advance();
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
   iterator.Advance();
   // Ignore compare operation.
   iterator.Advance();
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
   iterator.Advance();
@@ -650,13 +734,15 @@
   iterator.Advance();
   // Ignore compare operation.
   iterator.Advance();
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanFalse));
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
   CHECK_EQ(iterator.GetImmediateOperand(0), -409);
   iterator.Advance();
   // Ignore compare operation.
   iterator.Advance();
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
+  CHECK_EQ(iterator.current_bytecode(),
+           PeepholeToBoolean(Bytecode::kJumpIfToBooleanTrue));
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
   CHECK_EQ(iterator.GetImmediateOperand(0), -419);
   iterator.Advance();
@@ -675,9 +761,15 @@
 
   // Labels can only have 1 forward reference, but
   // can be referred to mulitple times once bound.
-  BytecodeLabel label;
+  BytecodeLabel label, after_jump0, after_jump1;
 
-  builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
+  builder.Jump(&label)
+      .Bind(&label)
+      .Jump(&label)
+      .Bind(&after_jump0)
+      .Jump(&label)
+      .Bind(&after_jump1)
+      .Return();
 
   Handle<BytecodeArray> array = builder.ToBytecodeArray();
   BytecodeArrayIterator iterator(array);
@@ -701,8 +793,13 @@
 
   BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
   for (int i = 0; i < kRepeats; i++) {
-    BytecodeLabel label;
-    builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
+    BytecodeLabel label, after_jump0, after_jump1;
+    builder.Jump(&label)
+        .Bind(&label)
+        .Jump(&label)
+        .Bind(&after_jump0)
+        .Jump(&label)
+        .Bind(&after_jump1);
   }
   builder.Return();
 
diff --git a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
index aa9effe..6b7374e 100644
--- a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
+++ b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc
@@ -47,14 +47,16 @@
       .LoadLiteral(smi_1)
       .StoreAccumulatorInRegister(reg_1)
       .LoadAccumulatorWithRegister(reg_0)
+      .BinaryOperation(Token::Value::ADD, reg_0)
       .StoreAccumulatorInRegister(reg_1)
       .LoadNamedProperty(reg_1, name, feedback_slot)
+      .BinaryOperation(Token::Value::ADD, reg_0)
       .StoreAccumulatorInRegister(param)
       .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, 1, reg_0)
       .ForInPrepare(reg_0)
       .CallRuntime(Runtime::kLoadIC_Miss, reg_0, 1)
       .Debugger()
-      .LoadGlobal(name, 0x10000000, TypeofMode::NOT_INSIDE_TYPEOF)
+      .LoadGlobal(0x10000000, TypeofMode::NOT_INSIDE_TYPEOF)
       .Return();
 
   // Test iterator sees the expected output from the builder.
@@ -155,6 +157,15 @@
   offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle);
   iterator.Advance();
 
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kAdd);
+  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::kStar);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
@@ -164,14 +175,23 @@
   offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
   iterator.Advance();
 
-  CHECK_EQ(iterator.current_bytecode(), Bytecode::kLoadIC);
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaNamedProperty);
   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.GetIndexOperand(1), name_index);
   CHECK_EQ(iterator.GetIndexOperand(2), feedback_slot);
   CHECK(!iterator.done());
-  offset += Bytecodes::Size(Bytecode::kLoadIC, OperandScale::kSingle);
+  offset += Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle);
+  iterator.Advance();
+
+  CHECK_EQ(iterator.current_bytecode(), Bytecode::kAdd);
+  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::kStar);
@@ -209,8 +229,7 @@
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kCallRuntime);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
-  CHECK_EQ(static_cast<Runtime::FunctionId>(iterator.GetRuntimeIdOperand(0)),
-           Runtime::kLoadIC_Miss);
+  CHECK_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadIC_Miss);
   CHECK_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index());
   CHECK_EQ(iterator.GetRegisterCountOperand(2), 1);
   CHECK(!iterator.done());
@@ -227,8 +246,8 @@
   CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaGlobal);
   CHECK_EQ(iterator.current_offset(), offset);
   CHECK_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple);
-  CHECK_EQ(iterator.current_bytecode_size(), 10);
-  CHECK_EQ(iterator.GetIndexOperand(1), 0x10000000);
+  CHECK_EQ(iterator.current_bytecode_size(), 6);
+  CHECK_EQ(iterator.GetIndexOperand(0), 0x10000000);
   offset += Bytecodes::Size(Bytecode::kLdaGlobal, OperandScale::kQuadruple) +
             kPrefixByteSize;
   iterator.Advance();
diff --git a/test/unittests/interpreter/bytecode-array-writer-unittest.cc b/test/unittests/interpreter/bytecode-array-writer-unittest.cc
index a1b4910..90a91ce 100644
--- a/test/unittests/interpreter/bytecode-array-writer-unittest.cc
+++ b/test/unittests/interpreter/bytecode-array-writer-unittest.cc
@@ -4,7 +4,11 @@
 
 #include "src/v8.h"
 
+#include "src/api.h"
+#include "src/factory.h"
 #include "src/interpreter/bytecode-array-writer.h"
+#include "src/interpreter/bytecode-label.h"
+#include "src/interpreter/constant-array-builder.h"
 #include "src/interpreter/source-position-table.h"
 #include "src/isolate.h"
 #include "src/utils.h"
@@ -18,39 +22,45 @@
 class BytecodeArrayWriterUnittest : public TestWithIsolateAndZone {
  public:
   BytecodeArrayWriterUnittest()
-      : source_position_builder_(isolate(), zone()),
-        bytecode_array_writer_(zone(), &source_position_builder_) {}
+      : constant_array_builder_(isolate(), zone()),
+        bytecode_array_writer_(isolate(), zone(), &constant_array_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,
+  void Write(Bytecode bytecode, uint32_t operand0,
              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,
+             uint32_t operand2,
              const BytecodeSourceInfo& info = BytecodeSourceInfo());
   void Write(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
-             uint32_t operand2, uint32_t operand3, OperandScale operand_scale,
+             uint32_t operand2, uint32_t operand3,
              const BytecodeSourceInfo& info = BytecodeSourceInfo());
 
-  SourcePositionTableBuilder* source_position_builder() {
-    return &source_position_builder_;
-  }
+  void WriteJump(Bytecode bytecode, BytecodeLabel* label,
+
+                 const BytecodeSourceInfo& info = BytecodeSourceInfo());
+
   BytecodeArrayWriter* writer() { return &bytecode_array_writer_; }
+  ZoneVector<unsigned char>* bytecodes() { return writer()->bytecodes(); }
+  SourcePositionTableBuilder* source_position_table_builder() {
+    return writer()->source_position_table_builder();
+  }
+  int max_register_count() { return writer()->max_register_count(); }
 
  private:
-  SourcePositionTableBuilder source_position_builder_;
+  ConstantArrayBuilder constant_array_builder_;
   BytecodeArrayWriter bytecode_array_writer_;
 };
 
 void BytecodeArrayWriterUnittest::Write(BytecodeNode* node,
                                         const BytecodeSourceInfo& info) {
   if (info.is_valid()) {
-    node->source_info().Update(info);
+    node->source_info().Clone(info);
   }
   writer()->Write(node);
 }
@@ -62,72 +72,76 @@
 }
 
 void BytecodeArrayWriterUnittest::Write(Bytecode bytecode, uint32_t operand0,
-                                        OperandScale operand_scale,
                                         const BytecodeSourceInfo& info) {
-  BytecodeNode node(bytecode, operand0, operand_scale);
+  BytecodeNode node(bytecode, operand0);
   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);
+  BytecodeNode node(bytecode, operand0, operand1);
   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);
+  BytecodeNode node(bytecode, operand0, operand1, operand2);
   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);
+  BytecodeNode node(bytecode, operand0, operand1, operand2, operand3);
   Write(&node, info);
 }
 
+void BytecodeArrayWriterUnittest::WriteJump(Bytecode bytecode,
+                                            BytecodeLabel* label,
+                                            const BytecodeSourceInfo& info) {
+  BytecodeNode node(bytecode, 0);
+  if (info.is_valid()) {
+    node.source_info().Clone(info);
+  }
+  writer()->WriteJump(&node, label);
+}
+
 TEST_F(BytecodeArrayWriterUnittest, SimpleExample) {
-  CHECK_EQ(writer()->bytecodes()->size(), 0);
+  CHECK_EQ(bytecodes()->size(), 0);
 
   Write(Bytecode::kStackCheck, {10, false});
-  CHECK_EQ(writer()->bytecodes()->size(), 1);
-  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0);
+  CHECK_EQ(bytecodes()->size(), 1);
+  CHECK_EQ(max_register_count(), 0);
 
-  Write(Bytecode::kLdaSmi, 0xff, OperandScale::kSingle, {55, true});
-  CHECK_EQ(writer()->bytecodes()->size(), 3);
-  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 0);
+  Write(Bytecode::kLdaSmi, 127, {55, true});
+  CHECK_EQ(bytecodes()->size(), 3);
+  CHECK_EQ(max_register_count(), 0);
 
-  Write(Bytecode::kLdar, Register(1).ToOperand(), OperandScale::kDouble);
-  CHECK_EQ(writer()->bytecodes()->size(), 7);
-  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+  Write(Bytecode::kLdar, Register(200).ToOperand());
+  CHECK_EQ(bytecodes()->size(), 7);
+  CHECK_EQ(max_register_count(), 201);
 
   Write(Bytecode::kReturn, {70, true});
-  CHECK_EQ(writer()->bytecodes()->size(), 8);
-  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 2 * kPointerSize);
+  CHECK_EQ(bytecodes()->size(), 8);
+  CHECK_EQ(max_register_count(), 201);
 
-  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));
+  static const uint8_t bytes[] = {B(StackCheck), B(LdaSmi), U8(127),  B(Wide),
+                                  B(Ldar),       R16(200),  B(Return)};
+  CHECK_EQ(bytecodes()->size(), arraysize(bytes));
   for (size_t i = 0; i < arraysize(bytes); ++i) {
-    CHECK_EQ(writer()->bytecodes()->at(i), bytes[i]);
+    CHECK_EQ(bytecodes()->at(i), bytes[i]);
   }
 
-  CHECK_EQ(writer()->FlushForOffset(), arraysize(bytes));
-  writer()->FlushBasicBlock();
-  CHECK_EQ(writer()->bytecodes()->size(), arraysize(bytes));
+  writer()->ToBytecodeArray(0, 0, factory()->empty_fixed_array());
+  CHECK_EQ(bytecodes()->size(), arraysize(bytes));
 
   PositionTableEntry expected_positions[] = {
       {0, 10, false}, {1, 55, true}, {7, 70, true}};
   Handle<ByteArray> source_positions =
-      source_position_builder()->ToSourcePositionTable();
+      source_position_table_builder()->ToSourcePositionTable();
   SourcePositionTableIterator source_iterator(*source_positions);
   for (size_t i = 0; i < arraysize(expected_positions); ++i) {
     const PositionTableEntry& expected = expected_positions[i];
@@ -173,50 +187,57 @@
       {0, 30, false}, {1, 42, true},   {3, 42, false}, {5, 68, true},
       {17, 63, true}, {31, 54, false}, {36, 85, true}, {44, 85, true}};
 
+  BytecodeLabel back_jump, jump_for_in, jump_end_1, jump_end_2, jump_end_3;
+
 #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::kLdaConstant, U8(0), {42, true});
+  CHECK_EQ(max_register_count(), 0);
+  Write(Bytecode::kStar, R(1), {42, false});
+  CHECK_EQ(max_register_count(), 2);
+  WriteJump(Bytecode::kJumpIfUndefined, &jump_end_1, {68, true});
+  WriteJump(Bytecode::kJumpIfNull, &jump_end_2);
   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);
+  CHECK_EQ(max_register_count(), 2);
+  Write(Bytecode::kStar, R(3));
+  CHECK_EQ(max_register_count(), 4);
+  Write(Bytecode::kForInPrepare, R(4));
+  CHECK_EQ(max_register_count(), 7);
   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);
+  CHECK_EQ(max_register_count(), 7);
+  Write(Bytecode::kStar, R(7));
+  CHECK_EQ(max_register_count(), 8);
+  writer()->BindLabel(&back_jump);
+  Write(Bytecode::kForInDone, R(7), R(6), {63, true});
+  CHECK_EQ(max_register_count(), 8);
+  WriteJump(Bytecode::kJumpIfTrue, &jump_end_3);
+  Write(Bytecode::kForInNext, R(3), R(7), R(4), U8(1));
+  WriteJump(Bytecode::kJumpIfUndefined, &jump_for_in);
+  Write(Bytecode::kStar, R(0));
   Write(Bytecode::kStackCheck, {54, false});
-  Write(Bytecode::kLdar, R(0), OperandScale::kSingle);
-  Write(Bytecode::kStar, R(2), OperandScale::kSingle);
+  Write(Bytecode::kLdar, R(0));
+  Write(Bytecode::kStar, R(2));
   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);
+  writer()->BindLabel(&jump_for_in);
+  Write(Bytecode::kForInStep, R(7));
+  Write(Bytecode::kStar, R(7));
+  WriteJump(Bytecode::kJump, &back_jump);
+  writer()->BindLabel(&jump_end_1);
+  writer()->BindLabel(&jump_end_2);
+  writer()->BindLabel(&jump_end_3);
   Write(Bytecode::kLdaUndefined);
   Write(Bytecode::kReturn, {85, true});
-  CHECK_EQ(writer()->GetMaximumFrameSizeUsed(), 8 * kPointerSize);
+  CHECK_EQ(max_register_count(), 8);
 #undef R
 
-  CHECK_EQ(writer()->bytecodes()->size(), arraysize(expected_bytes));
+  CHECK_EQ(bytecodes()->size(), arraysize(expected_bytes));
   for (size_t i = 0; i < arraysize(expected_bytes); ++i) {
-    CHECK_EQ(static_cast<int>(writer()->bytecodes()->at(i)),
+    CHECK_EQ(static_cast<int>(bytecodes()->at(i)),
              static_cast<int>(expected_bytes[i]));
   }
 
   Handle<ByteArray> source_positions =
-      source_position_builder()->ToSourcePositionTable();
+      source_position_table_builder()->ToSourcePositionTable();
   SourcePositionTableIterator source_iterator(*source_positions);
   for (size_t i = 0; i < arraysize(expected_positions); ++i) {
     const PositionTableEntry& expected = expected_positions[i];
diff --git a/test/unittests/interpreter/bytecode-dead-code-optimizer-unittest.cc b/test/unittests/interpreter/bytecode-dead-code-optimizer-unittest.cc
new file mode 100644
index 0000000..915c23d
--- /dev/null
+++ b/test/unittests/interpreter/bytecode-dead-code-optimizer-unittest.cc
@@ -0,0 +1,149 @@
+// 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-dead-code-optimizer.h"
+#include "src/interpreter/bytecode-label.h"
+#include "src/objects.h"
+#include "test/unittests/test-utils.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+class BytecodeDeadCodeOptimizerTest : public BytecodePipelineStage,
+                                      public TestWithIsolateAndZone {
+ public:
+  BytecodeDeadCodeOptimizerTest() : dead_code_optimizer_(this) {}
+  ~BytecodeDeadCodeOptimizerTest() override {}
+
+  void Write(BytecodeNode* node) override {
+    write_count_++;
+    last_written_.Clone(node);
+  }
+
+  void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
+    write_count_++;
+    last_written_.Clone(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>();
+  }
+
+  BytecodeDeadCodeOptimizer* optimizer() { return &dead_code_optimizer_; }
+
+  int write_count() const { return write_count_; }
+  const BytecodeNode& last_written() const { return last_written_; }
+
+ private:
+  BytecodeDeadCodeOptimizer dead_code_optimizer_;
+
+  int write_count_ = 0;
+  BytecodeNode last_written_;
+};
+
+TEST_F(BytecodeDeadCodeOptimizerTest, LiveCodeKept) {
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(add, last_written());
+
+  BytecodeLabel target;
+  BytecodeNode jump(Bytecode::kJump, 0);
+  optimizer()->WriteJump(&jump, &target);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(jump, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterReturnEliminated) {
+  BytecodeNode ret(Bytecode::kReturn);
+  optimizer()->Write(&ret);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterThrowEliminated) {
+  BytecodeNode thrw(Bytecode::kThrow);
+  optimizer()->Write(&thrw);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(thrw, last_written());
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(thrw, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterReThrowEliminated) {
+  BytecodeNode rethrow(Bytecode::kReThrow);
+  optimizer()->Write(&rethrow);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(rethrow, last_written());
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(rethrow, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeAfterJumpEliminated) {
+  BytecodeLabel target;
+  BytecodeNode jump(Bytecode::kJump, 0);
+  optimizer()->WriteJump(&jump, &target);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(jump, last_written());
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(jump, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, DeadCodeStillDeadAfterConditinalJump) {
+  BytecodeNode ret(Bytecode::kReturn);
+  optimizer()->Write(&ret);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+
+  BytecodeLabel target;
+  BytecodeNode jump(Bytecode::kJumpIfTrue, 0);
+  optimizer()->WriteJump(&jump, &target);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+}
+
+TEST_F(BytecodeDeadCodeOptimizerTest, CodeLiveAfterLabelBind) {
+  BytecodeNode ret(Bytecode::kReturn);
+  optimizer()->Write(&ret);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(ret, last_written());
+
+  BytecodeLabel target;
+  optimizer()->BindLabel(&target);
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(add, last_written());
+}
+
+}  // 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
index cf4a920..671bdf8 100644
--- a/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc
+++ b/test/unittests/interpreter/bytecode-peephole-optimizer-unittest.cc
@@ -5,6 +5,7 @@
 #include "src/v8.h"
 
 #include "src/factory.h"
+#include "src/interpreter/bytecode-label.h"
 #include "src/interpreter/bytecode-peephole-optimizer.h"
 #include "src/interpreter/constant-array-builder.h"
 #include "src/objects-inl.h"
@@ -23,23 +24,31 @@
         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);
   }
 
+  void WriteJump(BytecodeNode* node, BytecodeLabel* label) override {
+    write_count_++;
+    last_written_.Clone(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>();
+  }
+
+  void Flush() {
+    optimizer()->ToBytecodeArray(0, 0, factory()->empty_fixed_array());
+  }
+
   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_; }
 
@@ -47,96 +56,98 @@
   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, FlushOnJump) {
+  CHECK_EQ(write_count(), 0);
+
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  CHECK_EQ(write_count(), 0);
+
+  BytecodeLabel target;
+  BytecodeNode jump(Bytecode::kJump, 0);
+  optimizer()->WriteJump(&jump, &target);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(jump, last_written());
 }
 
-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);
+TEST_F(BytecodePeepholeOptimizerTest, FlushOnBind) {
   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);
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
   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();
+  BytecodeLabel target;
+  optimizer()->BindLabel(&target);
   CHECK_EQ(write_count(), 1);
-  CHECK_EQ(node, last_written());
+  CHECK_EQ(add, last_written());
+}
+
+// Nop elimination tests.
+
+TEST_F(BytecodePeepholeOptimizerTest, ElideEmptyNop) {
+  BytecodeNode nop(Bytecode::kNop);
+  optimizer()->Write(&nop);
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  Flush();
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(add, last_written());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, ElideExpressionNop) {
+  BytecodeNode nop(Bytecode::kNop);
+  nop.source_info().MakeExpressionPosition(3);
+  optimizer()->Write(&nop);
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  optimizer()->Write(&add);
+  Flush();
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(add, last_written());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, KeepStatementNop) {
+  BytecodeNode nop(Bytecode::kNop);
+  nop.source_info().MakeStatementPosition(3);
+  optimizer()->Write(&nop);
+  BytecodeNode add(Bytecode::kAdd, Register(0).ToOperand());
+  add.source_info().MakeExpressionPosition(3);
+  optimizer()->Write(&add);
+  Flush();
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(add, last_written());
 }
 
 // Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode().
 
 TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) {
   BytecodeNode first(Bytecode::kLdaNull);
-  BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3, OperandScale::kSingle);
+  BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3);
   optimizer()->Write(&first);
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   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);
+  BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3);
   optimizer()->Write(&first);
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 2);
   CHECK_EQ(last_written().bytecode(), Bytecode::kJumpIfTrue);
   CHECK_EQ(last_written().operand(0), second.operand(0));
@@ -150,7 +161,7 @@
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 2);
   CHECK_EQ(last_written(), second);
 }
@@ -163,95 +174,81 @@
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   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);
+TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRy) {
+  BytecodeNode first(Bytecode::kStar, Register(0).ToOperand());
+  BytecodeNode second(Bytecode::kLdar, Register(1).ToOperand());
   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();
+  Flush();
   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);
+TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRx) {
+  BytecodeLabel label;
+  BytecodeNode first(Bytecode::kStar, Register(0).ToOperand());
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand());
   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();
+  Flush();
   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});
+TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatement) {
+  BytecodeNode first(Bytecode::kStar, Register(0).ToOperand());
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand());
+  second.source_info().MakeStatementPosition(0);
   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();
+  Flush();
   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});
+TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRxStatementStarRy) {
+  BytecodeLabel label;
+  BytecodeNode first(Bytecode::kStar, Register(0).ToOperand());
+  BytecodeNode second(Bytecode::kLdar, Register(0).ToOperand());
+  BytecodeNode third(Bytecode::kStar, Register(3).ToOperand());
+  second.source_info().MakeStatementPosition(0);
   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();
+  Flush();
   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 first(Bytecode::kLdar, Register(0).ToOperand());
   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();
+  Flush();
   CHECK_EQ(write_count(), 2);
   CHECK_EQ(last_written(), second);
 }
@@ -264,7 +261,7 @@
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
 }
 
@@ -276,7 +273,7 @@
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), first);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
 }
 
@@ -284,50 +281,34 @@
   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 first(Bytecode::kLdaConstant, static_cast<uint32_t>(index));
   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();
+  Flush();
   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 first(Bytecode::kLdaConstant, static_cast<uint32_t>(index));
   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();
+  Flush();
   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);
@@ -335,23 +316,24 @@
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 0);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), second);
 }
 
 TEST_F(BytecodePeepholeOptimizerTest, LdaTrueStatementLdaFalse) {
   BytecodeNode first(Bytecode::kLdaTrue);
-  first.source_info().Update({3, false});
+  first.source_info().MakeExpressionPosition(3);
   BytecodeNode second(Bytecode::kLdaFalse);
   optimizer()->Write(&first);
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 0);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
-  second.source_info().Update(first.source_info());
   CHECK_EQ(last_written(), second);
+  CHECK(second.source_info().is_expression());
+  CHECK_EQ(second.source_info().source_position(), 3);
 }
 
 TEST_F(BytecodePeepholeOptimizerTest, NopStackCheck) {
@@ -361,25 +343,152 @@
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 0);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
   CHECK_EQ(last_written(), second);
 }
 
 TEST_F(BytecodePeepholeOptimizerTest, NopStatementStackCheck) {
   BytecodeNode first(Bytecode::kNop);
-  first.source_info().Update({3, false});
+  first.source_info().MakeExpressionPosition(3);
   BytecodeNode second(Bytecode::kStackCheck);
   optimizer()->Write(&first);
   CHECK_EQ(write_count(), 0);
   optimizer()->Write(&second);
   CHECK_EQ(write_count(), 0);
-  optimizer()->FlushBasicBlock();
+  Flush();
   CHECK_EQ(write_count(), 1);
-  second.source_info().Update(first.source_info());
+  second.source_info().MakeExpressionPosition(
+      first.source_info().source_position());
   CHECK_EQ(last_written(), second);
 }
 
+// Tests covering BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes().
+
+TEST_F(BytecodePeepholeOptimizerTest, MergeLoadICStar) {
+  const uint32_t operands[] = {
+      static_cast<uint32_t>(Register(31).ToOperand()), 32, 33,
+      static_cast<uint32_t>(Register(256).ToOperand())};
+  const int expected_operand_count = static_cast<int>(arraysize(operands));
+
+  BytecodeNode first(Bytecode::kLdaNamedProperty, operands[0], operands[1],
+                     operands[2]);
+  BytecodeNode second(Bytecode::kStar, operands[3]);
+  BytecodeNode third(Bytecode::kReturn);
+  optimizer()->Write(&first);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdrNamedProperty);
+  CHECK_EQ(last_written().operand_count(), expected_operand_count);
+  for (int i = 0; i < expected_operand_count; ++i) {
+    CHECK_EQ(last_written().operand(i), operands[i]);
+  }
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
+  CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
+  Flush();
+  CHECK_EQ(last_written().bytecode(), third.bytecode());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, MergeLdaKeyedPropertyStar) {
+  const uint32_t operands[] = {static_cast<uint32_t>(Register(31).ToOperand()),
+                               9999997,
+                               static_cast<uint32_t>(Register(1).ToOperand())};
+  const int expected_operand_count = static_cast<int>(arraysize(operands));
+
+  BytecodeNode first(Bytecode::kLdaKeyedProperty, operands[0], operands[1]);
+  BytecodeNode second(Bytecode::kStar, operands[2]);
+  BytecodeNode third(Bytecode::kReturn);
+  optimizer()->Write(&first);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdrKeyedProperty);
+  CHECK_EQ(last_written().operand_count(), expected_operand_count);
+  for (int i = 0; i < expected_operand_count; ++i) {
+    CHECK_EQ(last_written().operand(i), operands[i]);
+  }
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
+  CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
+  Flush();
+  CHECK_EQ(last_written().bytecode(), third.bytecode());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, MergeLdaGlobalStar) {
+  const uint32_t operands[] = {19191,
+                               static_cast<uint32_t>(Register(1).ToOperand())};
+  const int expected_operand_count = static_cast<int>(arraysize(operands));
+
+  BytecodeNode first(Bytecode::kLdaGlobal, operands[0]);
+  BytecodeNode second(Bytecode::kStar, operands[1]);
+  BytecodeNode third(Bytecode::kReturn);
+  optimizer()->Write(&first);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdrGlobal);
+  CHECK_EQ(last_written().operand_count(), expected_operand_count);
+  for (int i = 0; i < expected_operand_count; ++i) {
+    CHECK_EQ(last_written().operand(i), operands[i]);
+  }
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
+  CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
+  Flush();
+  CHECK_EQ(last_written().bytecode(), third.bytecode());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, MergeLdaContextSlotStar) {
+  const uint32_t operands[] = {
+      static_cast<uint32_t>(Register(200000).ToOperand()), 55005500,
+      static_cast<uint32_t>(Register(1).ToOperand())};
+  const int expected_operand_count = static_cast<int>(arraysize(operands));
+
+  BytecodeNode first(Bytecode::kLdaContextSlot, operands[0], operands[1]);
+  BytecodeNode second(Bytecode::kStar, operands[2]);
+  BytecodeNode third(Bytecode::kReturn);
+  optimizer()->Write(&first);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdrContextSlot);
+  CHECK_EQ(last_written().operand_count(), expected_operand_count);
+  for (int i = 0; i < expected_operand_count; ++i) {
+    CHECK_EQ(last_written().operand(i), operands[i]);
+  }
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
+  CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
+  Flush();
+  CHECK_EQ(last_written().bytecode(), third.bytecode());
+}
+
+TEST_F(BytecodePeepholeOptimizerTest, MergeLdaUndefinedStar) {
+  const uint32_t operands[] = {
+      static_cast<uint32_t>(Register(100000).ToOperand())};
+  const int expected_operand_count = static_cast<int>(arraysize(operands));
+
+  BytecodeNode first(Bytecode::kLdaUndefined);
+  BytecodeNode second(Bytecode::kStar, operands[0]);
+  BytecodeNode third(Bytecode::kReturn);
+  optimizer()->Write(&first);
+  optimizer()->Write(&second);
+  CHECK_EQ(write_count(), 1);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdrUndefined);
+  CHECK_EQ(last_written().operand_count(), expected_operand_count);
+  for (int i = 0; i < expected_operand_count; ++i) {
+    CHECK_EQ(last_written().operand(i), operands[i]);
+  }
+  optimizer()->Write(&third);
+  CHECK_EQ(write_count(), 2);
+  CHECK_EQ(last_written().bytecode(), Bytecode::kLdar);
+  CHECK_EQ(last_written().operand(0), operands[expected_operand_count - 1]);
+  Flush();
+  CHECK_EQ(last_written().bytecode(), third.bytecode());
+}
+
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8
diff --git a/test/unittests/interpreter/bytecode-pipeline-unittest.cc b/test/unittests/interpreter/bytecode-pipeline-unittest.cc
index f12391c..663b7e5 100644
--- a/test/unittests/interpreter/bytecode-pipeline-unittest.cc
+++ b/test/unittests/interpreter/bytecode-pipeline-unittest.cc
@@ -24,7 +24,7 @@
   CHECK_EQ(x.is_statement(), false);
   CHECK_EQ(x.is_valid(), false);
 
-  x.Update({1, true});
+  x.MakeStatementPosition(1);
   BytecodeSourceInfo y(1, true);
   CHECK(x == y);
   CHECK(!(x != y));
@@ -33,20 +33,20 @@
   CHECK(!(x == y));
   CHECK(x != y);
 
-  y.Update({2, false});
+  y.MakeStatementPosition(1);
   CHECK_EQ(y.source_position(), 1);
   CHECK_EQ(y.is_statement(), true);
 
-  y.Update({2, true});
+  y.MakeStatementPosition(2);
   CHECK_EQ(y.source_position(), 2);
   CHECK_EQ(y.is_statement(), true);
 
   y.set_invalid();
-  y.Update({3, false});
+  y.MakeExpressionPosition(3);
   CHECK_EQ(y.source_position(), 3);
   CHECK_EQ(y.is_statement(), false);
 
-  y.Update({3, true});
+  y.MakeStatementPosition(3);
   CHECK_EQ(y.source_position(), 3);
   CHECK_EQ(y.is_statement(), true);
 }
@@ -61,100 +61,88 @@
   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);
+  BytecodeNode node(Bytecode::kJumpIfTrue, operands[0]);
   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);
+  uint32_t operands[] = {0x11};
+  BytecodeNode node(Bytecode::kLdaGlobal, operands[0]);
   CHECK_EQ(node.bytecode(), Bytecode::kLdaGlobal);
-  CHECK_EQ(node.operand_count(), 2);
+  CHECK_EQ(node.operand_count(), 1);
   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);
+  BytecodeNode node(Bytecode::kLdaNamedProperty, operands[0], operands[1],
+                    operands[2]);
   CHECK_EQ(node.operand_count(), 3);
-  CHECK_EQ(node.bytecode(), Bytecode::kLoadIC);
+  CHECK_EQ(node.bytecode(), Bytecode::kLdaNamedProperty);
   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);
+                    operands[3]);
   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);
+                    operands[3]);
   CHECK_EQ(node, node);
   BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
-                     operands[2], operands[3], OperandScale::kDouble);
+                     operands[2], operands[3]);
   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});
+                    operands[3]);
+  node.source_info().MakeStatementPosition(3);
   CHECK_EQ(node, node);
   BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
-                     operands[2], operands[3], OperandScale::kDouble);
-  other.source_info().Update({3, true});
+                     operands[2], operands[3]);
+  other.source_info().MakeStatementPosition(3);
   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});
+                    operands[3]);
+  node.source_info().MakeStatementPosition(3);
   BytecodeNode other(Bytecode::kForInNext, operands[0], operands[1],
-                     operands[2], operands[3], OperandScale::kDouble);
+                     operands[2], operands[3]);
   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);
+                    operands[3]);
   BytecodeNode clone;
   clone.Clone(&node);
   CHECK_EQ(clone, node);
@@ -163,33 +151,32 @@
 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);
+                    operands[3]);
   BytecodeSourceInfo source_info(77, false);
-  node.source_info().Update(source_info);
+  node.source_info().Clone(source_info);
+  CHECK_EQ(node.source_info(), 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);
+                    operands[3]);
   BytecodeSourceInfo source_info(77, false);
-  node.source_info().Update(source_info);
+  node.source_info().Clone(source_info);
 
   BytecodeNode clone;
   clone.Clone(&node);
-  clone.set_bytecode(Bytecode::kJump, 0x01aabbcc, OperandScale::kQuadruple);
+  clone.set_bytecode(Bytecode::kJump, 0x01aabbcc);
   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);
 }
 
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
diff --git a/test/unittests/interpreter/bytecodes-unittest.cc b/test/unittests/interpreter/bytecodes-unittest.cc
index eebacb2..74a2bb3 100644
--- a/test/unittests/interpreter/bytecodes-unittest.cc
+++ b/test/unittests/interpreter/bytecodes-unittest.cc
@@ -254,35 +254,6 @@
   }
 }
 
-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);
@@ -366,7 +337,6 @@
   names.insert(Bytecodes::AccumulatorUseToString(AccumulatorUse::kReadWrite));
   CHECK_EQ(names.size(), 4);
 }
-
 }  // namespace interpreter
 }  // namespace internal
 }  // namespace v8
diff --git a/test/unittests/interpreter/constant-array-builder-unittest.cc b/test/unittests/interpreter/constant-array-builder-unittest.cc
index 7122437..c48ac58 100644
--- a/test/unittests/interpreter/constant-array-builder-unittest.cc
+++ b/test/unittests/interpreter/constant-array-builder-unittest.cc
@@ -89,7 +89,7 @@
     }
     for (size_t i = 0; i < reserved; i++) {
       size_t index = k8BitCapacity - reserved + i;
-      CHECK(builder.At(index)->IsTheHole());
+      CHECK(builder.At(index)->IsTheHole(isolate()));
     }
 
     // Now make reservations, and commit them with unique entries.
diff --git a/test/unittests/interpreter/interpreter-assembler-unittest.cc b/test/unittests/interpreter/interpreter-assembler-unittest.cc
index cd21f09..1bc80c0 100644
--- a/test/unittests/interpreter/interpreter-assembler-unittest.cc
+++ b/test/unittests/interpreter/interpreter-assembler-unittest.cc
@@ -428,6 +428,10 @@
             EXPECT_THAT(m.BytecodeOperandRuntimeId(i),
                         m.IsUnsignedOperand(offset, operand_size));
             break;
+          case interpreter::OperandType::kIntrinsicId:
+            EXPECT_THAT(m.BytecodeOperandIntrinsicId(i),
+                        m.IsUnsignedOperand(offset, operand_size));
+            break;
           case interpreter::OperandType::kNone:
             UNREACHABLE();
             break;
@@ -692,16 +696,14 @@
         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 -
-                                  kHeapObjectTag));
+    Matcher<Node*> load_literals_matcher = m.IsLoad(
+        MachineType::AnyTagged(), load_function_matcher,
+        IsIntPtrConstant(JSFunction::kLiteralsOffset - kHeapObjectTag));
 
-    EXPECT_THAT(
-        feedback_vector,
-        m.IsLoad(MachineType::AnyTagged(), load_shared_function_info_matcher,
-                 IsIntPtrConstant(SharedFunctionInfo::kFeedbackVectorOffset -
-                                  kHeapObjectTag)));
+    EXPECT_THAT(feedback_vector,
+                m.IsLoad(MachineType::AnyTagged(), load_literals_matcher,
+                         IsIntPtrConstant(LiteralsArray::kFeedbackVectorOffset -
+                                          kHeapObjectTag)));
   }
 }
 
diff --git a/test/unittests/interpreter/source-position-table-unittest.cc b/test/unittests/interpreter/source-position-table-unittest.cc
index 230e57d..87d58fd 100644
--- a/test/unittests/interpreter/source-position-table-unittest.cc
+++ b/test/unittests/interpreter/source-position-table-unittest.cc
@@ -56,23 +56,26 @@
 TEST_F(SourcePositionTableTest, EncodeAscending) {
   SourcePositionTableBuilder builder(isolate(), zone());
 
-  int accumulator = 0;
+  int code_offset = 0;
+  int source_position = 0;
   for (int i = 0; i < arraysize(offsets); i++) {
-    accumulator += offsets[i];
+    code_offset += offsets[i];
+    source_position += offsets[i];
     if (i % 2) {
-      builder.AddPosition(accumulator, accumulator, true);
+      builder.AddPosition(code_offset, source_position, true);
     } else {
-      builder.AddPosition(accumulator, accumulator, false);
+      builder.AddPosition(code_offset, source_position, false);
     }
   }
 
-  // Also test negative offsets:
+  // Also test negative offsets for source positions:
   for (int i = 0; i < arraysize(offsets); i++) {
-    accumulator -= offsets[i];
+    code_offset += offsets[i];
+    source_position -= offsets[i];
     if (i % 2) {
-      builder.AddPosition(accumulator, accumulator, true);
+      builder.AddPosition(code_offset, source_position, true);
     } else {
-      builder.AddPosition(accumulator, accumulator, false);
+      builder.AddPosition(code_offset, source_position, false);
     }
   }