diff --git a/BUILD.gn b/BUILD.gn index 48b35ba52d..afa418a1b4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1444,8 +1444,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-random-iterator.cc", + "src/interpreter/bytecode-array-random-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/DEPS b/src/DEPS index dc924f799c..e9026b130d 100644 --- a/src/DEPS +++ b/src/DEPS @@ -12,7 +12,7 @@ include_rules = [ "-src/interpreter", "+src/interpreter/bytecode-array-accessor.h", "+src/interpreter/bytecode-array-iterator.h", - "+src/interpreter/bytecode-array-reverse-iterator.h", + "+src/interpreter/bytecode-array-random-iterator.h", "+src/interpreter/bytecode-decoder.h", "+src/interpreter/bytecode-flags.h", "+src/interpreter/bytecode-register.h", diff --git a/src/compiler/bytecode-analysis.cc b/src/compiler/bytecode-analysis.cc index 8d077abc9f..40e4563894 100644 --- a/src/compiler/bytecode-analysis.cc +++ b/src/compiler/bytecode-analysis.cc @@ -5,7 +5,7 @@ #include "src/compiler/bytecode-analysis.h" #include "src/interpreter/bytecode-array-iterator.h" -#include "src/interpreter/bytecode-array-reverse-iterator.h" +#include "src/interpreter/bytecode-array-random-iterator.h" #include "src/objects-inl.h" namespace v8 { @@ -20,6 +20,7 @@ BytecodeAnalysis::BytecodeAnalysis(Handle bytecode_array, do_liveness_analysis_(do_liveness_analysis), zone_(zone), loop_stack_(zone), + loop_end_index_queue_(zone), end_to_header_(zone), header_to_parent_(zone), liveness_map_(bytecode_array->length(), zone) {} @@ -151,12 +152,8 @@ void BytecodeAnalysis::Analyze() { BitVector* next_bytecode_in_liveness = nullptr; - // The last JumpLoop that we haven't done a guaranteed valid liveness pass - // over. See the below wall of text for a more thorough explanation. - int last_invalid_jumploop_offset = -1; - - BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); - for (; !iterator.done(); iterator.Advance()) { + BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); + for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { Bytecode bytecode = iterator.current_bytecode(); int current_offset = iterator.current_offset(); @@ -166,9 +163,9 @@ void BytecodeAnalysis::Analyze() { int loop_end = current_offset + iterator.current_bytecode_size(); PushLoop(iterator.GetJumpTargetOffset(), loop_end); - // Save the last offset so that we can do another pass later. - if (last_invalid_jumploop_offset == -1) { - last_invalid_jumploop_offset = current_offset; + // Save the index so that we can do another pass later. + if (do_liveness_analysis_) { + loop_end_index_queue_.push_back(iterator.current_index()); } } else if (current_offset == loop_stack_.top()) { loop_stack_.pop(); @@ -214,69 +211,48 @@ void BytecodeAnalysis::Analyze() { // This means that in a pass, we can iterate backwards over the bytecode // array, process any loops that we encounter, and on subsequent passes we can // skip processing those loops (though we still have to process inner loops). + // + // Equivalently, we can queue up loop ends from back to front, and pass over + // the loops in that order, as this preserves both the bottom-to-top and + // outer-to-inner requirements. - while (last_invalid_jumploop_offset != -1) { - // TODO(leszeks): We shouldn't need to iterate here, we should just have a - // random access iterator. - iterator.Reset(); - while (last_invalid_jumploop_offset < iterator.current_offset()) { - iterator.Advance(); - } - last_invalid_jumploop_offset = -1; + for (int loop_end_index : loop_end_index_queue_) { + iterator.GoToIndex(loop_end_index); DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop); - for (; !iterator.done(); iterator.Advance()) { - Bytecode bytecode = iterator.current_bytecode(); - if (bytecode != Bytecode::kJumpLoop) { - // Skip bytecodes until we hit a JumpLoop. This check isn't needed for - // the first loop we see (thanks to saving its offset), but it is for - // subsequent ones we want to process on this pass. - continue; - } + int header_offset = iterator.GetJumpTargetOffset(); + int end_offset = iterator.current_offset(); - int header_offset = iterator.GetJumpTargetOffset(); - int end_offset = iterator.current_offset(); + Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); + Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); - Liveness& header_liveness = liveness_map_.GetLiveness(header_offset); - Liveness& end_liveness = liveness_map_.GetLiveness(end_offset); - - if (end_liveness.out->UnionIsChanged(*header_liveness.in)) { - // Only update the loop body if the loop end liveness changed. - end_liveness.in->CopyFrom(*end_liveness.out); - next_bytecode_in_liveness = end_liveness.in; - - // Advance into the loop body. - iterator.Advance(); - for (; iterator.current_offset() > header_offset; iterator.Advance()) { - bytecode = iterator.current_bytecode(); - if (bytecode == Bytecode::kJumpLoop) { - // We can't validate this loop at the moment because we can't - // guarantee that its header is valid yet. Save it for later. - if (last_invalid_jumploop_offset == -1) { - last_invalid_jumploop_offset = iterator.current_offset(); - } - } - - int current_offset = iterator.current_offset(); - Liveness& liveness = liveness_map_.GetLiveness(current_offset); - - UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, - iterator, liveness_map_); - liveness.in->CopyFrom(*liveness.out); - UpdateInLiveness(bytecode, *liveness.in, iterator); - - next_bytecode_in_liveness = liveness.in; - } - // Now we are at the loop header. Since the in-liveness of the header - // can't change, we need only to update the out-liveness. - bytecode = iterator.current_bytecode(); - UpdateOutLiveness(bytecode, *header_liveness.out, - next_bytecode_in_liveness, iterator, liveness_map_); - } - - // Keep the iterator going so that we can find other loops. + if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) { + // Only update the loop body if the loop end liveness changed. + continue; } + end_liveness.in->CopyFrom(*end_liveness.out); + next_bytecode_in_liveness = end_liveness.in; + + // Advance into the loop body. + --iterator; + for (; iterator.current_offset() > header_offset; --iterator) { + Bytecode bytecode = iterator.current_bytecode(); + + int current_offset = iterator.current_offset(); + Liveness& liveness = liveness_map_.GetLiveness(current_offset); + + UpdateOutLiveness(bytecode, *liveness.out, next_bytecode_in_liveness, + iterator, liveness_map_); + liveness.in->CopyFrom(*liveness.out); + UpdateInLiveness(bytecode, *liveness.in, iterator); + + next_bytecode_in_liveness = liveness.in; + } + // Now we are at the loop header. Since the in-liveness of the header + // can't change, we need only to update the out-liveness. + UpdateOutLiveness(iterator.current_bytecode(), *header_liveness.out, + next_bytecode_in_liveness, iterator, liveness_map_); } DCHECK(LivenessIsValid()); @@ -376,7 +352,7 @@ std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const { #if DEBUG bool BytecodeAnalysis::LivenessIsValid() { - BytecodeArrayReverseIterator iterator(bytecode_array(), zone()); + BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); BitVector previous_liveness(bytecode_array()->register_count() + 1, zone()); @@ -386,7 +362,7 @@ bool BytecodeAnalysis::LivenessIsValid() { BitVector* next_bytecode_in_liveness = nullptr; // Ensure that there are no liveness changes if we iterate one more time. - for (iterator.Reset(); !iterator.done(); iterator.Advance()) { + for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { Bytecode bytecode = iterator.current_bytecode(); int current_offset = iterator.current_offset(); diff --git a/src/compiler/bytecode-analysis.h b/src/compiler/bytecode-analysis.h index 9baba84f92..00f7ab5a75 100644 --- a/src/compiler/bytecode-analysis.h +++ b/src/compiler/bytecode-analysis.h @@ -66,6 +66,7 @@ class V8_EXPORT_PRIVATE BytecodeAnalysis BASE_EMBEDDED { Zone* zone_; ZoneStack loop_stack_; + ZoneVector loop_end_index_queue_; ZoneMap end_to_header_; ZoneMap header_to_parent_; diff --git a/src/interpreter/bytecode-array-reverse-iterator.cc b/src/interpreter/bytecode-array-random-iterator.cc similarity index 55% rename from src/interpreter/bytecode-array-reverse-iterator.cc rename to src/interpreter/bytecode-array-random-iterator.cc index d4be64eaa1..f499887ccb 100644 --- a/src/interpreter/bytecode-array-reverse-iterator.cc +++ b/src/interpreter/bytecode-array-random-iterator.cc @@ -2,14 +2,14 @@ // 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/interpreter/bytecode-array-random-iterator.h" #include "src/objects-inl.h" namespace v8 { namespace internal { namespace interpreter { -BytecodeArrayReverseIterator::BytecodeArrayReverseIterator( +BytecodeArrayRandomIterator::BytecodeArrayRandomIterator( Handle bytecode_array, Zone* zone) : BytecodeArrayAccessor(bytecode_array, 0), offsets_(zone) { // Run forwards through the bytecode array to determine the offset of each @@ -18,26 +18,17 @@ BytecodeArrayReverseIterator::BytecodeArrayReverseIterator( offsets_.push_back(current_offset()); SetOffset(current_offset() + current_bytecode_size()); } - Reset(); + GoToStart(); } -void BytecodeArrayReverseIterator::Advance() { - it_offsets_++; - UpdateOffsetFromIterator(); +bool BytecodeArrayRandomIterator::IsValid() const { + return current_index_ >= 0 && + static_cast(current_index_) < offsets_.size(); } -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_); +void BytecodeArrayRandomIterator::UpdateOffsetFromIndex() { + if (IsValid()) { + SetOffset(offsets_[current_index_]); } } diff --git a/src/interpreter/bytecode-array-random-iterator.h b/src/interpreter/bytecode-array-random-iterator.h new file mode 100644 index 0000000000..7d559ea176 --- /dev/null +++ b/src/interpreter/bytecode-array-random-iterator.h @@ -0,0 +1,78 @@ +// 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_RANDOM_ITERATOR_H_ +#define V8_INTERPRETER_BYTECODE_ARRAY_RANDOM_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 BytecodeArrayRandomIterator final + : public BytecodeArrayAccessor { + public: + explicit BytecodeArrayRandomIterator(Handle bytecode_array, + Zone* zone); + + BytecodeArrayRandomIterator& operator++() { + ++current_index_; + UpdateOffsetFromIndex(); + return *this; + } + BytecodeArrayRandomIterator& operator--() { + --current_index_; + UpdateOffsetFromIndex(); + return *this; + } + + BytecodeArrayRandomIterator& operator+=(int offset) { + current_index_ += offset; + UpdateOffsetFromIndex(); + return *this; + } + + BytecodeArrayRandomIterator& operator-=(int offset) { + current_index_ -= offset; + UpdateOffsetFromIndex(); + return *this; + } + + int current_index() const { return current_index_; } + + size_t size() const { return offsets_.size(); } + + void GoToIndex(int index) { + current_index_ = index; + UpdateOffsetFromIndex(); + } + void GoToStart() { + current_index_ = 0; + UpdateOffsetFromIndex(); + } + void GoToEnd() { + DCHECK_LT(offsets_.size() - 1, static_cast(INT_MAX)); + current_index_ = static_cast(offsets_.size() - 1); + UpdateOffsetFromIndex(); + } + + bool IsValid() const; + + private: + ZoneVector offsets_; + int current_index_; + + void UpdateOffsetFromIndex(); + + DISALLOW_COPY_AND_ASSIGN(BytecodeArrayRandomIterator); +}; + +} // namespace interpreter +} // namespace internal +} // namespace v8 + +#endif // V8_INTERPRETER_BYTECODE_ARRAY_RANDOM_ITERATOR_H_ diff --git a/src/interpreter/bytecode-array-reverse-iterator.h b/src/interpreter/bytecode-array-reverse-iterator.h deleted file mode 100644 index 42c9e7ce27..0000000000 --- a/src/interpreter/bytecode-array-reverse-iterator.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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 579d066ff1..def9539d0e 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -982,8 +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-random-iterator.cc', + 'interpreter/bytecode-array-random-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 36d1079e52..a9c63709fa 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -99,7 +99,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-random-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-random-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc new file mode 100644 index 0000000000..0e532305dd --- /dev/null +++ b/test/unittests/interpreter/bytecode-array-random-iterator-unittest.cc @@ -0,0 +1,1010 @@ +// 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-random-iterator.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +class BytecodeArrayRandomIteratorTest : public TestWithIsolateAndZone { + public: + BytecodeArrayRandomIteratorTest() {} + ~BytecodeArrayRandomIteratorTest() override {} +}; + +TEST_F(BytecodeArrayRandomIteratorTest, InvalidBeforeStart) { + // 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 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(); + + Handle bytecodeArray = builder.ToBytecodeArray(isolate()); + BytecodeArrayRandomIterator iterator(bytecodeArray, zone()); + + iterator.GoToStart(); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + ASSERT_FALSE(iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, InvalidAfterEnd) { + // 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 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(); + + Handle bytecodeArray = builder.ToBytecodeArray(isolate()); + BytecodeArrayRandomIterator iterator(bytecodeArray, zone()); + + iterator.GoToEnd(); + ASSERT_TRUE(iterator.IsValid()); + ++iterator; + ASSERT_FALSE(iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, AccessesFirst) { + // 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 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(); + + Handle bytecodeArray = builder.ToBytecodeArray(isolate()); + BytecodeArrayRandomIterator iterator(bytecodeArray, zone()); + + iterator.GoToStart(); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 0); + EXPECT_EQ(iterator.current_offset(), 0); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_0)); + ASSERT_TRUE(iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, AccessesLast) { + // 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 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(); + + Handle bytecodeArray = builder.ToBytecodeArray(isolate()); + BytecodeArrayRandomIterator iterator(bytecodeArray, zone()); + + iterator.GoToEnd(); + + int offset = bytecodeArray->length() - + Bytecodes::Size(Bytecode::kReturn, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kReturn); + EXPECT_EQ(iterator.current_index(), 23); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, RandomAccessValid) { + // 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. + BytecodeArrayRandomIterator iterator(builder.ToBytecodeArray(isolate()), + zone()); + const int kPrefixByteSize = 1; + int offset = 0; + + iterator.GoToIndex(13); + offset = Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) + + kPrefixByteSize; + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kAdd); + EXPECT_EQ(iterator.current_index(), 13); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + + iterator.GoToIndex(2); + offset = Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 2); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_1)); + ASSERT_TRUE(iterator.IsValid()); + + iterator.GoToIndex(18); + offset = Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) + + kPrefixByteSize; + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kCallRuntimeForPair); + EXPECT_EQ(iterator.current_index(), 18); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadLookupSlotForCall); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(1), 1); + EXPECT_EQ(iterator.GetRegisterCountOperand(2), 1u); + EXPECT_EQ(iterator.GetRegisterOperand(3).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(3), 2); + ASSERT_TRUE(iterator.IsValid()); + + iterator -= 3; + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset -= Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + offset -= Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaNamedProperty); + EXPECT_EQ(iterator.current_index(), 15); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetIndexOperand(1), name_index); + EXPECT_EQ(iterator.GetIndexOperand(2), feedback_slot); + ASSERT_TRUE(iterator.IsValid()); + + iterator += 2; + offset += Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 17); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + + iterator.GoToIndex(23); + offset = Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) + + kPrefixByteSize; + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + offset += + Bytecodes::Size(Bytecode::kCallRuntimeForPair, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kForInPrepare, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kCallRuntime, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kDebugger, OperandScale::kSingle); + offset += Bytecodes::Size(Bytecode::kLdaGlobal, OperandScale::kQuadruple) + + kPrefixByteSize; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kReturn); + EXPECT_EQ(iterator.current_index(), 23); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + + iterator.GoToIndex(24); + EXPECT_FALSE(iterator.IsValid()); + + iterator.GoToIndex(-5); + EXPECT_FALSE(iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, 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. + BytecodeArrayRandomIterator iterator(builder.ToBytecodeArray(isolate()), + zone()); + const int kPrefixByteSize = 1; + int offset = 0; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 0); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_0)); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 1); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 2); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_1)); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 3); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaZero); + EXPECT_EQ(iterator.current_index(), 4); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 5); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi); + EXPECT_EQ(iterator.current_index(), 6); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_0); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStackCheck); + EXPECT_EQ(iterator.current_index(), 7); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 8); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi); + EXPECT_EQ(iterator.current_index(), 9); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple); + EXPECT_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) + + kPrefixByteSize; + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStackCheck); + EXPECT_EQ(iterator.current_index(), 10); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 11); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdar); + EXPECT_EQ(iterator.current_index(), 12); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kAdd); + EXPECT_EQ(iterator.current_index(), 13); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 14); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaNamedProperty); + EXPECT_EQ(iterator.current_index(), 15); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetIndexOperand(1), name_index); + EXPECT_EQ(iterator.GetIndexOperand(2), feedback_slot); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kAdd); + EXPECT_EQ(iterator.current_index(), 16); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 17); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kCallRuntimeForPair); + EXPECT_EQ(iterator.current_index(), 18); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadLookupSlotForCall); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(1), 1); + EXPECT_EQ(iterator.GetRegisterCountOperand(2), 1u); + EXPECT_EQ(iterator.GetRegisterOperand(3).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(3), 2); + ASSERT_TRUE(iterator.IsValid()); + offset += + Bytecodes::Size(Bytecode::kCallRuntimeForPair, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kForInPrepare); + EXPECT_EQ(iterator.current_index(), 19); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(1), 3); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kForInPrepare, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kCallRuntime); + EXPECT_EQ(iterator.current_index(), 20); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadIC_Miss); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterCountOperand(2), 1u); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kCallRuntime, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kDebugger); + EXPECT_EQ(iterator.current_index(), 21); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + offset += Bytecodes::Size(Bytecode::kDebugger, OperandScale::kSingle); + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaGlobal); + EXPECT_EQ(iterator.current_index(), 22); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple); + EXPECT_EQ(iterator.current_bytecode_size(), 10); + EXPECT_EQ(iterator.GetIndexOperand(1), 0x10000000u); + offset += Bytecodes::Size(Bytecode::kLdaGlobal, OperandScale::kQuadruple) + + kPrefixByteSize; + ++iterator; + + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kReturn); + EXPECT_EQ(iterator.current_index(), 23); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + ++iterator; + ASSERT_TRUE(!iterator.IsValid()); +} + +TEST_F(BytecodeArrayRandomIteratorTest, IteratesBytecodeArrayBackwards) { + // 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()); + BytecodeArrayRandomIterator iterator(bytecodeArray, zone()); + const int kPrefixByteSize = 1; + int offset = bytecodeArray->length(); + + iterator.GoToEnd(); + + offset -= Bytecodes::Size(Bytecode::kReturn, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kReturn); + EXPECT_EQ(iterator.current_index(), 23); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaGlobal, OperandScale::kQuadruple) + + kPrefixByteSize; + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaGlobal); + EXPECT_EQ(iterator.current_index(), 22); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple); + EXPECT_EQ(iterator.current_bytecode_size(), 10); + EXPECT_EQ(iterator.GetIndexOperand(1), 0x10000000u); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kDebugger, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kDebugger); + EXPECT_EQ(iterator.current_index(), 21); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kCallRuntime, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kCallRuntime); + EXPECT_EQ(iterator.current_index(), 20); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadIC_Miss); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterCountOperand(2), 1u); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kForInPrepare, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kForInPrepare); + EXPECT_EQ(iterator.current_index(), 19); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(1), 3); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= + Bytecodes::Size(Bytecode::kCallRuntimeForPair, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kCallRuntimeForPair); + EXPECT_EQ(iterator.current_index(), 18); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRuntimeIdOperand(0), Runtime::kLoadLookupSlotForCall); + EXPECT_EQ(iterator.GetRegisterOperand(1).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(1), 1); + EXPECT_EQ(iterator.GetRegisterCountOperand(2), 1u); + EXPECT_EQ(iterator.GetRegisterOperand(3).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(3), 2); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 17); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), param.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kAdd); + EXPECT_EQ(iterator.current_index(), 16); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaNamedProperty, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaNamedProperty); + EXPECT_EQ(iterator.current_index(), 15); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetIndexOperand(1), name_index); + EXPECT_EQ(iterator.GetIndexOperand(2), feedback_slot); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 14); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kAdd, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kAdd); + EXPECT_EQ(iterator.current_index(), 13); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdar); + EXPECT_EQ(iterator.current_index(), 12); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 11); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_1.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStackCheck); + EXPECT_EQ(iterator.current_index(), 10); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kQuadruple) + + kPrefixByteSize; + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi); + EXPECT_EQ(iterator.current_index(), 9); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kQuadruple); + EXPECT_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 8); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStackCheck, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStackCheck); + EXPECT_EQ(iterator.current_index(), 7); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Bytecodes::NumberOfOperands(iterator.current_bytecode()), 0); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaSmi, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaSmi); + EXPECT_EQ(iterator.current_index(), 6); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(Smi::FromInt(iterator.GetImmediateOperand(0)), smi_0); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 5); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaZero, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaZero); + EXPECT_EQ(iterator.current_index(), 4); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 3); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 2); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_1)); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kStar, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kStar); + EXPECT_EQ(iterator.current_index(), 1); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_EQ(iterator.GetRegisterOperand(0).index(), reg_0.index()); + EXPECT_EQ(iterator.GetRegisterOperandRange(0), 1); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + + offset -= Bytecodes::Size(Bytecode::kLdaConstant, OperandScale::kSingle); + EXPECT_EQ(iterator.current_bytecode(), Bytecode::kLdaConstant); + EXPECT_EQ(iterator.current_index(), 0); + EXPECT_EQ(iterator.current_offset(), offset); + EXPECT_EQ(iterator.current_operand_scale(), OperandScale::kSingle); + EXPECT_TRUE( + iterator.GetConstantForIndexOperand(0).is_identical_to(heap_num_0)); + ASSERT_TRUE(iterator.IsValid()); + --iterator; + ASSERT_FALSE(iterator.IsValid()); +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 diff --git a/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc deleted file mode 100644 index 0782cc8e59..0000000000 --- a/test/unittests/interpreter/bytecode-array-reverse-iterator-unittest.cc +++ /dev/null @@ -1,288 +0,0 @@ -// 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 4d5ab4e660..121e882274 100644 --- a/test/unittests/unittests.gyp +++ b/test/unittests/unittests.gyp @@ -90,7 +90,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-random-iterator-unittest.cc', 'interpreter/bytecode-array-writer-unittest.cc', 'interpreter/bytecode-dead-code-optimizer-unittest.cc', 'interpreter/bytecode-decoder-unittest.cc',