[ignition] Add a reverse bytecode iterator

This pre-calculates and stores a vector of bytecode offsets, and then allows
one to iterate over it backwards. This could probably be adapted to a
bidirectional/random access iterator if we wanted to, but for now reverse
is all we need.

Review-Url: https://codereview.chromium.org/2518003002
Cr-Commit-Position: refs/heads/master@{#41153}
This commit is contained in:
leszeks 2016-11-21 09:20:48 -08:00 committed by Commit bot
parent ae8a77ea5f
commit f91178e823
7 changed files with 379 additions and 0 deletions

View File

@ -1446,6 +1446,8 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-array-builder.h",
"src/interpreter/bytecode-array-iterator.cc",
"src/interpreter/bytecode-array-iterator.h",
"src/interpreter/bytecode-array-reverse-iterator.cc",
"src/interpreter/bytecode-array-reverse-iterator.h",
"src/interpreter/bytecode-array-writer.cc",
"src/interpreter/bytecode-array-writer.h",
"src/interpreter/bytecode-dead-code-optimizer.cc",

View File

@ -0,0 +1,46 @@
// 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.
#include "src/interpreter/bytecode-array-reverse-iterator.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
namespace interpreter {
BytecodeArrayReverseIterator::BytecodeArrayReverseIterator(
Handle<BytecodeArray> bytecode_array, Zone* zone)
: BytecodeArrayAccessor(bytecode_array, 0), offsets_(zone) {
// Run forwards through the bytecode array to determine the offset of each
// bytecode.
while (current_offset() < bytecode_array->length()) {
offsets_.push_back(current_offset());
SetOffset(current_offset() + current_bytecode_size());
}
Reset();
}
void BytecodeArrayReverseIterator::Advance() {
it_offsets_++;
UpdateOffsetFromIterator();
}
void BytecodeArrayReverseIterator::Reset() {
it_offsets_ = offsets_.rbegin();
UpdateOffsetFromIterator();
}
bool BytecodeArrayReverseIterator::done() const {
return it_offsets_ == offsets_.rend();
}
void BytecodeArrayReverseIterator::UpdateOffsetFromIterator() {
if (it_offsets_ != offsets_.rend()) {
SetOffset(*it_offsets_);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,39 @@
// 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.
#ifndef V8_INTERPRETER_BYTECODE_ARRAY_REVERSE_ITERATOR_H_
#define V8_INTERPRETER_BYTECODE_ARRAY_REVERSE_ITERATOR_H_
#include "src/interpreter/bytecode-array-accessor.h"
#include "src/zone/zone-containers.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace interpreter {
class V8_EXPORT_PRIVATE BytecodeArrayReverseIterator final
: public BytecodeArrayAccessor {
public:
explicit BytecodeArrayReverseIterator(Handle<BytecodeArray> bytecode_array,
Zone* zone);
void Advance();
void Reset();
bool done() const;
private:
ZoneVector<int> offsets_;
ZoneVector<int>::const_reverse_iterator it_offsets_;
void UpdateOffsetFromIterator();
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayReverseIterator);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_ARRAY_REVERSE_ITERATOR_H_

View File

@ -982,6 +982,8 @@
'interpreter/bytecode-array-builder.h',
'interpreter/bytecode-array-iterator.cc',
'interpreter/bytecode-array-iterator.h',
'interpreter/bytecode-array-reverse-iterator.cc',
'interpreter/bytecode-array-reverse-iterator.h',
'interpreter/bytecode-array-writer.cc',
'interpreter/bytecode-array-writer.h',
'interpreter/bytecode-dead-code-optimizer.cc',

View File

@ -98,6 +98,7 @@ v8_executable("unittests") {
"heap/slot-set-unittest.cc",
"interpreter/bytecode-array-builder-unittest.cc",
"interpreter/bytecode-array-iterator-unittest.cc",
"interpreter/bytecode-array-reverse-iterator-unittest.cc",
"interpreter/bytecode-array-writer-unittest.cc",
"interpreter/bytecode-dead-code-optimizer-unittest.cc",
"interpreter/bytecode-decoder-unittest.cc",

View File

@ -0,0 +1,288 @@
// 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.
#include "src/v8.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-array-reverse-iterator.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayReverseIteratorTest : public TestWithIsolateAndZone {
public:
BytecodeArrayReverseIteratorTest() {}
~BytecodeArrayReverseIteratorTest() override {}
};
TEST_F(BytecodeArrayReverseIteratorTest, IteratesBytecodeArray) {
// Use a builder to create an array with containing multiple bytecodes
// with 0, 1 and 2 operands.
BytecodeArrayBuilder builder(isolate(), zone(), 3, 3, 0);
Factory* factory = isolate()->factory();
Handle<HeapObject> heap_num_0 = factory->NewHeapNumber(2.718);
Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(2147483647);
Smi* zero = Smi::kZero;
Smi* smi_0 = Smi::FromInt(64);
Smi* smi_1 = Smi::FromInt(-65536);
Register reg_0(0);
Register reg_1(1);
RegisterList pair(0, 2);
RegisterList triple(0, 3);
Register param = Register::FromParameterIndex(2, builder.parameter_count());
Handle<String> name = factory->NewStringFromStaticChars("abc");
uint32_t name_index = 2;
uint32_t 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)
.StackCheck(0)
.StoreAccumulatorInRegister(reg_0)
.LoadLiteral(smi_1)
.StackCheck(1)
.StoreAccumulatorInRegister(reg_1)
.LoadAccumulatorWithRegister(reg_0)
.BinaryOperation(Token::Value::ADD, reg_0, 2)
.StoreAccumulatorInRegister(reg_1)
.LoadNamedProperty(reg_1, name, feedback_slot)
.BinaryOperation(Token::Value::ADD, reg_0, 3)
.StoreAccumulatorInRegister(param)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, pair)
.ForInPrepare(reg_0, triple)
.CallRuntime(Runtime::kLoadIC_Miss, reg_0)
.Debugger()
.LoadGlobal(name, 0x10000000, TypeofMode::NOT_INSIDE_TYPEOF)
.Return();
// Test iterator sees the expected output from the builder.
Handle<BytecodeArray> bytecodeArray = builder.ToBytecodeArray(isolate());
BytecodeArrayReverseIterator iterator(bytecodeArray, zone());
const int kPrefixByteSize = 1;
int offset = bytecodeArray->length();
offset -= Bytecodes::Size(Bytecode::kReturn, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaGlobal, OperandScale::kQuadruple) +
kPrefixByteSize;
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), 0x10000000u);
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kDebugger, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kCallRuntime, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kCallRuntime);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadIC_Miss);
CHECK_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index());
CHECK_EQ(iterator.GetRegisterCountOperand(2), 1u);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kForInPrepare, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kForInPrepare);
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_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index());
CHECK_EQ(iterator.GetRegisterOperandRange(1), 3);
CHECK(!iterator.done());
iterator.Advance();
offset -=
Bytecodes::Size(Bytecode::kCallRuntimeForPair, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kCallRuntimeForPair);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadLookupSlotForCall);
CHECK_EQ(iterator.GetRegisterOperand(1).index(), param.index());
CHECK_EQ(iterator.GetRegisterOperandRange(1), 1);
CHECK_EQ(iterator.GetRegisterCountOperand(2), 1u);
CHECK_EQ(iterator.GetRegisterOperand(3).index(), reg_0.index());
CHECK_EQ(iterator.GetRegisterOperandRange(3), 2);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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(), param.index());
CHECK_EQ(iterator.GetRegisterOperandRange(0), 1);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdar);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index());
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kStackCheck);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) +
kPrefixByteSize;
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple);
CHECK_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_1);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kStackCheck);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_0);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaZero);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_1));
CHECK(!iterator.done());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle);
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());
iterator.Advance();
offset -= Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle);
CHECK_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant);
CHECK_EQ(iterator.current_offset(), offset);
CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
CHECK(iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_0));
CHECK(!iterator.done());
iterator.Advance();
CHECK(iterator.done());
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -89,6 +89,7 @@
'interpreter/bytecodes-unittest.cc',
'interpreter/bytecode-array-builder-unittest.cc',
'interpreter/bytecode-array-iterator-unittest.cc',
'interpreter/bytecode-array-reverse-iterator-unittest.cc',
'interpreter/bytecode-array-writer-unittest.cc',
'interpreter/bytecode-dead-code-optimizer-unittest.cc',
'interpreter/bytecode-decoder-unittest.cc',