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);
}
}