From f91178e8230522abdfbc9aeb089cc237a323baa8 Mon Sep 17 00:00:00 2001 From: leszeks Date: Mon, 21 Nov 2016 09:20:48 -0800 Subject: [PATCH] [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} --- BUILD.gn | 2 + .../bytecode-array-reverse-iterator.cc | 46 +++ .../bytecode-array-reverse-iterator.h | 39 +++ src/v8.gyp | 2 + test/unittests/BUILD.gn | 1 + ...ytecode-array-reverse-iterator-unittest.cc | 288 ++++++++++++++++++ test/unittests/unittests.gyp | 1 + 7 files changed, 379 insertions(+) create mode 100644 src/interpreter/bytecode-array-reverse-iterator.cc create mode 100644 src/interpreter/bytecode-array-reverse-iterator.h create mode 100644 test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc diff --git a/BUILD.gn b/BUILD.gn index bb062463a1..ec73657f64 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -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", diff --git a/src/interpreter/bytecode-array-reverse-iterator.cc b/src/interpreter/bytecode-array-reverse-iterator.cc new file mode 100644 index 0000000000..d4be64eaa1 --- /dev/null +++ b/src/interpreter/bytecode-array-reverse-iterator.cc @@ -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 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 diff --git a/src/interpreter/bytecode-array-reverse-iterator.h b/src/interpreter/bytecode-array-reverse-iterator.h new file mode 100644 index 0000000000..42c9e7ce27 --- /dev/null +++ b/src/interpreter/bytecode-array-reverse-iterator.h @@ -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 bytecode_array, + Zone* zone); + + void Advance(); + void Reset(); + bool done() const; + + private: + ZoneVector offsets_; + ZoneVector::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_ diff --git a/src/v8.gyp b/src/v8.gyp index 6b5dd8eda1..ba76b1cb34 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -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', diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn index 20b606925c..953bdbb314 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -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", diff --git a/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc new file mode 100644 index 0000000000..0782cc8e59 --- /dev/null +++ b/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc @@ -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 heap_num_0 = factory->NewHeapNumber(2.718); + Handle 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 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 = 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 diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp index 01e48e1f21..2f80100023 100644 --- a/test/unittests/unittests.gyp +++ b/test/unittests/unittests.gyp @@ -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',