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