Add DexInstructionIterator and use it a few places
Motivation:
Want to start abstracting away dex specific functionality to enable
CompactDex. Adding an iterator will enable CompactDex iteration to
work differently than normal dex iteration.
Will eventually replace CodeItemIterator.
Bug: 63756964
Test: test-art-host
Change-Id: I90e67c1a994b7698aaac0523a82816b0a003fbdc
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index e49f83f..7581962 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -374,8 +374,8 @@
// Dex pc is not serialized, only used for checking the instructions. Since we access the
// array based on the index of the quickened instruction, the indexes must line up perfectly.
// The reader side uses the NeedsIndexForInstruction function too.
- const Instruction* inst = Instruction::At(code_item->insns_ + info.dex_pc);
- CHECK(QuickenInfoTable::NeedsIndexForInstruction(inst)) << inst->Opcode();
+ const Instruction& inst = code_item->InstructionAt(info.dex_pc);
+ CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode();
// Add the index.
quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0));
quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8));
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc
index c8e3d5e..925863e 100644
--- a/compiler/dex/inline_method_analyser.cc
+++ b/compiler/dex/inline_method_analyser.cc
@@ -64,14 +64,14 @@
private:
explicit Matcher(const DexFile::CodeItem* code_item)
: code_item_(code_item),
- instruction_(Instruction::At(code_item->insns_)),
+ instruction_(code_item->Instructions().begin()),
pos_(0u),
mark_(0u) { }
static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
const DexFile::CodeItem* const code_item_;
- const Instruction* instruction_;
+ DexInstructionIterator instruction_;
size_t pos_;
size_t mark_;
};
@@ -93,7 +93,7 @@
return false;
}
matcher->pos_ += 1u;
- matcher->instruction_ = matcher->instruction_->Next();
+ ++matcher->instruction_;
return true;
}
@@ -105,7 +105,7 @@
return true;
}
matcher->pos_ = matcher->mark_;
- matcher->instruction_ = matcher->instruction_->Next();
+ ++matcher->instruction_;
return true;
}
@@ -301,26 +301,27 @@
// Verify the invoke, prevent a few odd cases and collect IPUTs.
uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
uint16_t zero_vreg_mask = 0u;
- for (const Instruction* instruction = Instruction::At(code_item->insns_);
- instruction->Opcode() != Instruction::RETURN_VOID;
- instruction = instruction->Next()) {
- if (instruction->Opcode() == Instruction::INVOKE_DIRECT) {
- ArtMethod* target_method = GetTargetConstructor(method, instruction);
+
+ for (const Instruction& instruction : code_item->Instructions()) {
+ if (instruction.Opcode() == Instruction::RETURN_VOID) {
+ break;
+ } else if (instruction.Opcode() == Instruction::INVOKE_DIRECT) {
+ ArtMethod* target_method = GetTargetConstructor(method, &instruction);
if (target_method == nullptr) {
return false;
}
// We allow forwarding constructors only if they pass more arguments
// to prevent infinite recursion.
if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
- instruction->VRegA_35c() <= code_item->ins_size_) {
+ instruction.VRegA_35c() <= code_item->ins_size_) {
return false;
}
- size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask);
+ size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask);
if (forwarded == static_cast<size_t>(-1)) {
return false;
}
if (target_method->GetDeclaringClass()->IsObjectClass()) {
- DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(),
+ DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(),
Instruction::RETURN_VOID);
} else {
const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
@@ -345,15 +346,15 @@
return false;
}
}
- } else if (IsInstructionDirectConst(instruction->Opcode())) {
- zero_vreg_mask |= GetZeroVRegMask(instruction);
+ } else if (IsInstructionDirectConst(instruction.Opcode())) {
+ zero_vreg_mask |= GetZeroVRegMask(&instruction);
if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
return false; // Overwriting `this` is unsupported.
}
} else {
- DCHECK(IsInstructionIPut(instruction->Opcode()));
- DCHECK_EQ(instruction->VRegB_22c(), this_vreg);
- if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) {
+ DCHECK(IsInstructionIPut(instruction.Opcode()));
+ DCHECK_EQ(instruction.VRegB_22c(), this_vreg);
+ if (!RecordConstructorIPut(method, &instruction, this_vreg, zero_vreg_mask, iputs)) {
return false;
}
}
@@ -447,8 +448,7 @@
// We currently support only plain return or 2-instruction methods.
DCHECK_NE(code_item->insns_size_in_code_units_, 0u);
- const Instruction* instruction = Instruction::At(code_item->insns_);
- Instruction::Code opcode = instruction->Opcode();
+ Instruction::Code opcode = code_item->Instructions().begin()->Opcode();
switch (opcode) {
case Instruction::RETURN_VOID:
@@ -519,7 +519,7 @@
bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item,
InlineMethod* result) {
- const Instruction* return_instruction = Instruction::At(code_item->insns_);
+ DexInstructionIterator return_instruction = code_item->Instructions().begin();
Instruction::Code return_opcode = return_instruction->Opcode();
uint32_t reg = return_instruction->VRegA_11x();
uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_;
@@ -541,7 +541,7 @@
bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item,
InlineMethod* result) {
- const Instruction* instruction = Instruction::At(code_item->insns_);
+ DexInstructionIterator instruction = code_item->Instructions().begin();
const Instruction* return_instruction = instruction->Next();
Instruction::Code return_opcode = return_instruction->Opcode();
if (return_opcode != Instruction::RETURN &&
@@ -575,7 +575,7 @@
bool is_static,
ArtMethod* method,
InlineMethod* result) {
- const Instruction* instruction = Instruction::At(code_item->insns_);
+ DexInstructionIterator instruction = code_item->Instructions().begin();
Instruction::Code opcode = instruction->Opcode();
DCHECK(IsInstructionIGet(opcode));
@@ -639,7 +639,7 @@
bool is_static,
ArtMethod* method,
InlineMethod* result) {
- const Instruction* instruction = Instruction::At(code_item->insns_);
+ DexInstructionIterator instruction = code_item->Instructions().begin();
Instruction::Code opcode = instruction->Opcode();
DCHECK(IsInstructionIPut(opcode));
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e46dc59..9c5b632 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -64,24 +64,21 @@
if (method_verifier->HasFailures()) {
return;
}
- const DexFile::CodeItem* code_item = method_verifier->CodeItem();
- const Instruction* inst = Instruction::At(code_item->insns_);
- const Instruction* end = Instruction::At(code_item->insns_ +
- code_item->insns_size_in_code_units_);
-
- for (; inst < end; inst = inst->Next()) {
- Instruction::Code code = inst->Opcode();
+ IterationRange<DexInstructionIterator> instructions = method_verifier->CodeItem()->Instructions();
+ for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+ const Instruction& inst = *it;
+ const Instruction::Code code = inst.Opcode();
if (code == Instruction::CHECK_CAST) {
- uint32_t dex_pc = inst->GetDexPc(code_item->insns_);
+ const uint32_t dex_pc = it.GetDexPC(instructions.begin());
if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) {
// Do not attempt to quicken this instruction, it's unreachable anyway.
continue;
}
const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
- inst->VRegA_21c()));
+ inst.VRegA_21c()));
const verifier::RegType& cast_type =
- method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
+ method_verifier->ResolveCheckedClass(dex::TypeIndex(inst.VRegB_21c()));
// Pass null for the method verifier to not record the VerifierDeps dependency
// if the types are not assignable.
if (cast_type.IsStrictlyAssignableFrom(reg_type, /* method_verifier */ nullptr)) {
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 03d8ef5..7573367 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -762,18 +762,14 @@
return;
}
- const uint16_t* code_ptr = code_item->insns_;
- const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_;
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-
- while (code_ptr < code_end) {
- const Instruction* inst = Instruction::At(code_ptr);
- switch (inst->Opcode()) {
+ for (const Instruction& inst : code_item->Instructions()) {
+ switch (inst.Opcode()) {
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO: {
- dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING)
- ? inst->VRegB_21c()
- : inst->VRegB_31c());
+ dex::StringIndex string_index((inst.Opcode() == Instruction::CONST_STRING)
+ ? inst.VRegB_21c()
+ : inst.VRegB_31c());
mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
CHECK(string != nullptr) << "Could not allocate a string when forcing determinism";
break;
@@ -782,8 +778,6 @@
default:
break;
}
-
- code_ptr += inst->SizeInCodeUnits();
}
}
@@ -2439,21 +2433,16 @@
if (clinit != nullptr) {
const DexFile::CodeItem* code_item = clinit->GetCodeItem();
DCHECK(code_item != nullptr);
- const Instruction* inst = Instruction::At(code_item->insns_);
-
- const uint32_t insns_size = code_item->insns_size_in_code_units_;
- for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
- if (inst->Opcode() == Instruction::CONST_STRING) {
+ for (const Instruction& inst : code_item->Instructions()) {
+ if (inst.Opcode() == Instruction::CONST_STRING) {
ObjPtr<mirror::String> s = class_linker->ResolveString(
- *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache);
+ *dex_file, dex::StringIndex(inst.VRegB_21c()), h_dex_cache);
CHECK(s != nullptr);
- } else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) {
+ } else if (inst.Opcode() == Instruction::CONST_STRING_JUMBO) {
ObjPtr<mirror::String> s = class_linker->ResolveString(
- *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache);
+ *dex_file, dex::StringIndex(inst.VRegB_31c()), h_dex_cache);
CHECK(s != nullptr);
}
- dex_pc += inst->SizeInCodeUnits();
- inst = inst->Next();
}
}
}
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index b8e4f32..3cb3792 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -722,12 +722,10 @@
}
}
ArenaVector<size_t> covered(loop_headers.size(), 0, graph.GetArena()->Adapter(kArenaAllocMisc));
- const uint16_t* code_ptr = code_item.insns_;
- const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
-
- size_t dex_pc = 0;
- while (code_ptr < code_end) {
- const Instruction& instruction = *Instruction::At(code_ptr);
+ IterationRange<DexInstructionIterator> instructions = code_item.Instructions();
+ for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+ const uint32_t dex_pc = it.GetDexPC(instructions.begin());
+ const Instruction& instruction = *it;
if (instruction.IsBranch()) {
uint32_t target = dex_pc + instruction.GetTargetOffset();
CheckCovers(target, graph, code_info, loop_headers, &covered);
@@ -743,8 +741,6 @@
CheckCovers(target, graph, code_info, loop_headers, &covered);
}
}
- dex_pc += instruction.SizeInCodeUnits();
- code_ptr += instruction.SizeInCodeUnits();
}
for (size_t i = 0; i < covered.size(); ++i) {
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index e832b10..6ad8036 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -368,17 +368,16 @@
};
dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations);
// Instruction-specific tweaks.
- const Instruction* const begin = Instruction::At(code_item_.insns_);
- const Instruction* const end = begin->RelativeAt(code_item_.insns_size_in_code_units_);
- for (const Instruction* inst = begin; inst < end; inst = inst->Next()) {
- switch (inst->Opcode()) {
+ IterationRange<DexInstructionIterator> instructions = code_item_.Instructions();
+ for (const Instruction& inst : instructions) {
+ switch (inst.Opcode()) {
case Instruction::MOVE_EXCEPTION: {
// Stop in native debugger after the exception has been moved.
// The compiler also expects the move at the start of basic block so
// we do not want to interfere by inserting native-debug-info before it.
- locations->ClearBit(inst->GetDexPc(code_item_.insns_));
- const Instruction* next = inst->Next();
- if (next < end) {
+ locations->ClearBit(inst.GetDexPc(code_item_.insns_));
+ const Instruction* next = inst.Next();
+ if (DexInstructionIterator(next) != instructions.end()) {
locations->SetBit(next->GetDexPc(code_item_.insns_));
}
break;
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index 5913832..0c944ce 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -185,21 +185,14 @@
std::vector<MethodId*>* method_ids,
std::vector<FieldId*>* field_ids) {
bool has_id = false;
- // Iterate over all instructions.
- const uint16_t* insns = code->Insns();
- for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
- const Instruction* instruction = Instruction::At(&insns[insn_idx]);
- const uint32_t insn_width = instruction->SizeInCodeUnits();
- if (insn_width == 0) {
- break;
- }
+ for (const Instruction& instruction : code->Instructions()) {
+ CHECK_GT(instruction.SizeInCodeUnits(), 0u);
has_id |= GetIdFromInstruction(collections,
- instruction,
+ &instruction,
type_ids,
string_ids,
method_ids,
field_ids);
- insn_idx += insn_width;
} // for
return has_id;
}
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 362c08b..5dcc87d 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -947,6 +947,11 @@
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+ IterationRange<DexInstructionIterator> Instructions() const {
+ return MakeIterationRange(DexInstructionIterator(Insns()),
+ DexInstructionIterator(Insns() + InsnsSize()));
+ }
+
private:
uint16_t registers_size_;
uint16_t ins_size_;
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 92a1366..095c960 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -1079,16 +1079,15 @@
code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
// Iterate over all instructions.
- const uint16_t* insns = code->Insns();
- for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
- const Instruction* instruction = Instruction::At(&insns[insn_idx]);
- const uint32_t insn_width = instruction->SizeInCodeUnits();
+ IterationRange<DexInstructionIterator> instructions = code->Instructions();
+ for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+ const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+ const uint32_t insn_width = inst->SizeInCodeUnits();
if (insn_width == 0) {
- fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
+ fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", dex_pc);
break;
}
- DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
- insn_idx += insn_width;
+ DumpInstruction(code, code_offset, dex_pc, insn_width, &*inst);
} // for
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index be78136..bcf007b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -905,26 +905,23 @@
if (code_item == nullptr) {
return;
}
- const size_t code_item_size = code_item->insns_size_in_code_units_;
- const uint16_t* code_ptr = code_item->insns_;
- const uint16_t* code_end = code_item->insns_ + code_item_size;
+ const uint16_t* code_ptr = code_item->insns_;
// If we inserted a new dex code item pointer, add to total code bytes.
if (dex_code_item_ptrs_.insert(code_ptr).second) {
- dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]);
+ dex_code_bytes_ += code_item->insns_size_in_code_units_ * sizeof(code_ptr[0]);
}
- while (code_ptr < code_end) {
- const Instruction* inst = Instruction::At(code_ptr);
- switch (inst->Opcode()) {
+ for (const Instruction& inst : code_item->Instructions()) {
+ switch (inst.Opcode()) {
case Instruction::CONST_STRING: {
- const dex::StringIndex string_index(inst->VRegB_21c());
+ const dex::StringIndex string_index(inst.VRegB_21c());
unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
++num_string_ids_from_code_;
break;
}
case Instruction::CONST_STRING_JUMBO: {
- const dex::StringIndex string_index(inst->VRegB_31c());
+ const dex::StringIndex string_index(inst.VRegB_31c());
unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index));
++num_string_ids_from_code_;
break;
@@ -932,8 +929,6 @@
default:
break;
}
-
- code_ptr += inst->SizeInCodeUnits();
}
}
@@ -1520,12 +1515,11 @@
void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
if (code_item != nullptr) {
- size_t i = 0;
- while (i < code_item->insns_size_in_code_units_) {
- const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
- os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5)
- << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str());
- i += instruction->SizeInCodeUnits();
+ IterationRange<DexInstructionIterator> instructions = code_item->Instructions();
+ for (auto it = instructions.begin(); it != instructions.end(); ++it) {
+ const size_t dex_pc = it.GetDexPC(instructions.begin());
+ os << StringPrintf("0x%04zx: ", dex_pc) << it->DumpHexLE(5)
+ << StringPrintf("\t| %s\n", it->DumpString(&dex_file).c_str());
}
}
}
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 4807427..ac91d52 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -21,9 +21,11 @@
#include <string>
#include <vector>
+#include "base/iteration_range.h"
#include "base/logging.h"
#include "base/value_object.h"
#include "dex_file_types.h"
+#include "dex_instruction_iterator.h"
#include "globals.h"
#include "jni.h"
#include "modifiers.h"
@@ -293,6 +295,15 @@
// Raw code_item.
struct CodeItem {
+ IterationRange<DexInstructionIterator> Instructions() const {
+ return { DexInstructionIterator(insns_),
+ DexInstructionIterator(insns_ + insns_size_in_code_units_)};
+ }
+
+ const Instruction& InstructionAt(uint32_t dex_pc) const {
+ return *Instruction::At(insns_ + dex_pc);
+ }
+
uint16_t registers_size_; // the number of registers used by this code
// (locals + parameters)
uint16_t ins_size_; // the number of words of incoming arguments to the method
diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex_instruction_iterator.h
new file mode 100644
index 0000000..6585875
--- /dev/null
+++ b/runtime/dex_instruction_iterator.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
+#define ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
+
+#include <iterator>
+
+#include "dex_instruction.h"
+#include "base/logging.h"
+
+namespace art {
+
+class DexInstructionIterator : public std::iterator<std::forward_iterator_tag, Instruction> {
+ public:
+ using Type = std::iterator<std::forward_iterator_tag, Instruction>::value_type;
+ using difference_type = typename std::iterator<std::forward_iterator_tag, Type>::difference_type;
+
+ DexInstructionIterator() = default;
+ DexInstructionIterator(const DexInstructionIterator&) = default;
+ DexInstructionIterator(DexInstructionIterator&&) = default;
+ DexInstructionIterator& operator=(const DexInstructionIterator&) = default;
+ DexInstructionIterator& operator=(DexInstructionIterator&&) = default;
+
+ explicit DexInstructionIterator(const Type* inst) : inst_(inst) {}
+ explicit DexInstructionIterator(const uint16_t* inst) : inst_(Type::At(inst)) {}
+
+ ALWAYS_INLINE bool operator==(const DexInstructionIterator& other) const {
+ return inst_ == other.inst_ || inst_ == nullptr || other.inst_ == nullptr;
+ }
+
+ // Value after modification.
+ DexInstructionIterator& operator++() {
+ inst_ = inst_->Next();
+ return *this;
+ }
+
+ // Value before modification.
+ DexInstructionIterator operator++(int) {
+ DexInstructionIterator temp = *this;
+ ++*this;
+ return temp;
+ }
+
+ const Type& operator*() const {
+ return *inst_;
+ }
+
+ const Type* operator->() const {
+ return &**this;
+ }
+
+ // Return the dex pc for an iterator compared to the code item begin.
+ uint32_t GetDexPC(const DexInstructionIterator& code_item_begin) {
+ return reinterpret_cast<const uint16_t*>(inst_) -
+ reinterpret_cast<const uint16_t*>(code_item_begin.inst_);
+ }
+
+ const Type* Inst() const {
+ return inst_;
+ }
+
+ private:
+ const Type* inst_ = nullptr;
+};
+
+static inline bool operator!=(const DexInstructionIterator& lhs,
+ const DexInstructionIterator& rhs) {
+ return !(lhs == rhs);
+}
+
+static inline bool operator<(const DexInstructionIterator& lhs,
+ const DexInstructionIterator& rhs) {
+ return lhs.Inst() < rhs.Inst();
+}
+
+static inline bool operator>(const DexInstructionIterator& lhs,
+ const DexInstructionIterator& rhs) {
+ return rhs < lhs;
+}
+
+static inline bool operator<=(const DexInstructionIterator& lhs,
+ const DexInstructionIterator& rhs) {
+ return !(rhs < lhs);
+}
+
+static inline bool operator>=(const DexInstructionIterator& lhs,
+ const DexInstructionIterator& rhs) {
+ return !(lhs < rhs);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_
diff --git a/runtime/dex_instruction_test.cc b/runtime/dex_instruction_test.cc
index 3f7ac57..48ed027 100644
--- a/runtime/dex_instruction_test.cc
+++ b/runtime/dex_instruction_test.cc
@@ -15,6 +15,7 @@
*/
#include "dex_instruction-inl.h"
+#include "dex_instruction_iterator.h"
#include "gtest/gtest.h"
namespace art {
@@ -73,7 +74,7 @@
Build45cc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
0xcafe /* arg_regs */, instruction);
- const Instruction* ins = Instruction::At(instruction);
+ DexInstructionIterator ins(instruction);
ASSERT_EQ(4u, ins->SizeInCodeUnits());
ASSERT_TRUE(ins->HasVRegA());
@@ -108,7 +109,7 @@
Build4rcc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
0xcafe /* arg_regs */, instruction);
- const Instruction* ins = Instruction::At(instruction);
+ DexInstructionIterator ins(instruction);
ASSERT_EQ(4u, ins->SizeInCodeUnits());
ASSERT_TRUE(ins->HasVRegA());
@@ -154,7 +155,7 @@
std::vector<uint16_t> args) {
uint16_t inst[6] = {};
Build35c(inst, code, method_idx, args);
- return Instruction::At(inst)->DumpString(nullptr);
+ return DexInstructionIterator(inst)->DumpString(nullptr);
}
TEST(Instruction, DumpString) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 211381c..eef2773 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1119,7 +1119,7 @@
const DexFile::CodeItem* code;
code = caller->GetCodeItem();
CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[dex_pc]);
+ const Instruction* instr = &code->InstructionAt(dex_pc);
Instruction::Code instr_code = instr->Opcode();
bool is_range;
switch (instr_code) {
@@ -2484,7 +2484,7 @@
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
const DexFile::CodeItem* code_item = caller_method->GetCodeItem();
DCHECK_LT(dex_pc, code_item->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
+ const Instruction* instr = &code_item->InstructionAt(dex_pc);
Instruction::Code instr_code = instr->Opcode();
DCHECK(instr_code == Instruction::INVOKE_INTERFACE ||
instr_code == Instruction::INVOKE_INTERFACE_RANGE)
@@ -2600,7 +2600,7 @@
ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
const DexFile::CodeItem* code = caller_method->GetCodeItem();
- const Instruction* inst = Instruction::At(&code->insns_[dex_pc]);
+ const Instruction* inst = &code->InstructionAt(dex_pc);
DCHECK(inst->Opcode() == Instruction::INVOKE_POLYMORPHIC ||
inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
const DexFile* dex_file = caller_method->GetDexFile();
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 71ab01e..fb37825 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -393,7 +393,7 @@
// create instruction data for invoke-direct {v0, v1} of method with fake index
uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
- const Instruction* inst = Instruction::At(inst_data);
+ DexInstructionIterator inst(inst_data);
JValue result;
ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
@@ -403,7 +403,7 @@
shadow_frame->SetVRegReference(0, reference_empty_string);
shadow_frame->SetVRegReference(1, string_arg);
- interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
+ interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result);
mirror::String* string_result = reinterpret_cast<mirror::String*>(result.GetL());
EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
@@ -1027,12 +1027,12 @@
// create instruction data for invoke-direct {v0, v1} of method with fake index
uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
- const Instruction* inst = Instruction::At(inst_data);
+ DexInstructionIterator inst(inst_data);
JValue result;
ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
shadow_frame->SetVRegDouble(0, 1.23);
- interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
+ interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result);
ObjPtr<mirror::String> string_result = reinterpret_cast<mirror::String*>(result.GetL());
ASSERT_TRUE(string_result != nullptr);
@@ -1187,12 +1187,12 @@
// create instruction data for invoke-direct {v0} of method with fake index
uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
- const Instruction* inst = Instruction::At(inst_data);
+ DexInstructionIterator inst(inst_data);
interpreter::DoCall<false, false>(boot_cp_init,
self,
*shadow_frame,
- inst,
+ &*inst,
inst_data[0],
&result);
CHECK(!self->IsExceptionPending());
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 1bd095a..ad01324 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -43,15 +43,12 @@
// instructions we are interested in profiling.
DCHECK(!method->IsNative());
- const DexFile::CodeItem& code_item = *method->GetCodeItem();
- const uint16_t* code_ptr = code_item.insns_;
- const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
-
- uint32_t dex_pc = 0;
std::vector<uint32_t> entries;
- while (code_ptr < code_end) {
- const Instruction& instruction = *Instruction::At(code_ptr);
- switch (instruction.Opcode()) {
+
+ IterationRange<DexInstructionIterator> instructions = method->GetCodeItem()->Instructions();
+ for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+ const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+ switch (inst->Opcode()) {
case Instruction::INVOKE_VIRTUAL:
case Instruction::INVOKE_VIRTUAL_RANGE:
case Instruction::INVOKE_VIRTUAL_QUICK:
@@ -64,8 +61,6 @@
default:
break;
}
- dex_pc += instruction.SizeInCodeUnits();
- code_ptr += instruction.SizeInCodeUnits();
}
// We always create a `ProfilingInfo` object, even if there is no instruction we are
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index e4ad55d..b789ac6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -616,18 +616,11 @@
}
static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) {
- const Instruction* inst = Instruction::At(code_item->insns_);
-
- uint32_t insns_size = code_item->insns_size_in_code_units_;
- for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
- if (inst->Opcode() == Instruction::MONITOR_ENTER) {
+ for (const Instruction& inst : code_item->Instructions()) {
+ if (inst.Opcode() == Instruction::MONITOR_ENTER) {
return true;
}
-
- dex_pc += inst->SizeInCodeUnits();
- inst = inst->Next();
}
-
return false;
}
@@ -683,7 +676,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ const Instruction* inst = &code_item_->InstructionAt(dex_pc);
return GetQuickFieldAccess(inst, register_line);
}
@@ -723,7 +716,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
+ const Instruction* inst = &code_item_->InstructionAt(dex_pc);
const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
return GetQuickInvokedMethod(inst, register_line, is_range, false);
}
@@ -929,9 +922,8 @@
// Note: this can fail before we touch any instruction, for the signature of a method. So
// add a check.
if (work_insn_idx_ < dex::kDexNoIndex) {
- const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
- const Instruction* inst = Instruction::At(insns);
- int opcode_flags = Instruction::FlagsOf(inst->Opcode());
+ const Instruction& inst = code_item_->InstructionAt(work_insn_idx_);
+ int opcode_flags = Instruction::FlagsOf(inst.Opcode());
if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
saved_line_->CopyFromLine(work_line_.get());
@@ -990,14 +982,12 @@
}
bool MethodVerifier::ComputeWidthsAndCountOps() {
- const uint16_t* insns = code_item_->insns_;
- size_t insns_size = code_item_->insns_size_in_code_units_;
- const Instruction* inst = Instruction::At(insns);
size_t new_instance_count = 0;
size_t monitor_enter_count = 0;
- size_t dex_pc = 0;
- while (dex_pc < insns_size) {
+ IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+ DexInstructionIterator inst = instructions.begin();
+ for ( ; inst < instructions.end(); ++inst) {
Instruction::Code opcode = inst->Opcode();
switch (opcode) {
case Instruction::APUT_OBJECT:
@@ -1019,15 +1009,14 @@
default:
break;
}
- size_t inst_size = inst->SizeInCodeUnits();
- GetInstructionFlags(dex_pc).SetIsOpcode();
- dex_pc += inst_size;
- inst = inst->RelativeAt(inst_size);
+ GetInstructionFlags(inst.GetDexPC(instructions.begin())).SetIsOpcode();
}
- if (dex_pc != insns_size) {
+ if (inst != instructions.end()) {
+ const size_t insns_size = code_item_->insns_size_in_code_units_;
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected ("
- << dex_pc << " vs. " << insns_size << ")";
+ << inst.GetDexPC(instructions.begin()) << " vs. "
+ << insns_size << ")";
return false;
}
@@ -1105,15 +1094,13 @@
template <bool kAllowRuntimeOnlyInstructions>
bool MethodVerifier::VerifyInstructions() {
- const Instruction* inst = Instruction::At(code_item_->insns_);
-
/* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */
GetInstructionFlags(0).SetBranchTarget();
GetInstructionFlags(0).SetCompileTimeInfoPoint();
-
- uint32_t insns_size = code_item_->insns_size_in_code_units_;
- for (uint32_t dex_pc = 0; dex_pc < insns_size;) {
- if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(inst, dex_pc)) {
+ IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+ for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+ const uint32_t dex_pc = inst.GetDexPC(instructions.begin());
+ if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&*inst, dex_pc)) {
DCHECK_NE(failures_.size(), 0U);
return false;
}
@@ -1134,8 +1121,6 @@
} else if (inst->IsReturn()) {
GetInstructionFlags(dex_pc).SetCompileTimeInfoPointAndReturn();
}
- dex_pc += inst->SizeInCodeUnits();
- inst = inst->Next();
}
return true;
}
@@ -1671,9 +1656,10 @@
}
vios->Stream() << "Dumping instructions and register lines:\n";
ScopedIndentation indent1(vios);
- const Instruction* inst = Instruction::At(code_item_->insns_);
- for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
- dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) {
+
+ IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+ for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+ const size_t dex_pc = inst.GetDexPC(instructions.begin());
RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
if (reg_line != nullptr) {
vios->Stream() << reg_line->Dump(this) << "\n";
@@ -1938,9 +1924,10 @@
* we are almost certainly going to have some dead code.
*/
int dead_start = -1;
- uint32_t insn_idx = 0;
- for (; insn_idx < insns_size;
- insn_idx += Instruction::At(code_item_->insns_ + insn_idx)->SizeInCodeUnits()) {
+
+ IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
+ for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) {
+ const uint32_t insn_idx = inst.GetDexPC(instructions.begin());
/*
* Switch-statement data doesn't get "visited" by scanner. It
* may or may not be preceded by a padding NOP (for alignment).
@@ -1956,8 +1943,9 @@
}
if (!GetInstructionFlags(insn_idx).IsVisited()) {
- if (dead_start < 0)
+ if (dead_start < 0) {
dead_start = insn_idx;
+ }
} else if (dead_start >= 0) {
LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
<< "-" << reinterpret_cast<void*>(insn_idx - 1);
@@ -1965,8 +1953,9 @@
}
}
if (dead_start >= 0) {
- LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start)
- << "-" << reinterpret_cast<void*>(insn_idx - 1);
+ LogVerifyInfo()
+ << "dead code " << reinterpret_cast<void*>(dead_start)
+ << "-" << reinterpret_cast<void*>(instructions.end().GetDexPC(instructions.begin()));
}
// To dump the state of the verify after a method, do something like:
// if (dex_file_->PrettyMethod(dex_method_idx_) ==
@@ -2340,17 +2329,17 @@
while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
prev_idx--;
}
- const Instruction* prev_inst = Instruction::At(code_item_->insns_ + prev_idx);
- switch (prev_inst->Opcode()) {
+ const Instruction& prev_inst = code_item_->InstructionAt(prev_idx);
+ switch (prev_inst.Opcode()) {
case Instruction::MOVE_OBJECT:
case Instruction::MOVE_OBJECT_16:
case Instruction::MOVE_OBJECT_FROM16:
- if (prev_inst->VRegB() == inst->VRegA_11x()) {
+ if (prev_inst.VRegB() == inst->VRegA_11x()) {
// Redo the copy. This won't change the register types, but update the lock status
// for the aliased register.
work_line_->CopyRegister1(this,
- prev_inst->VRegA(),
- prev_inst->VRegB(),
+ prev_inst.VRegA(),
+ prev_inst.VRegB(),
kTypeCategoryRef);
}
break;
@@ -2648,7 +2637,7 @@
break;
}
- const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx);
+ const Instruction* instance_of_inst = &code_item_->InstructionAt(instance_of_idx);
/* Check for peep-hole pattern of:
* ...;
@@ -2710,7 +2699,7 @@
work_insn_idx_)) {
break;
}
- const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx);
+ const Instruction* move_inst = &code_item_->InstructionAt(move_idx);
switch (move_inst->Opcode()) {
case Instruction::MOVE_OBJECT:
if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) {
@@ -3648,7 +3637,7 @@
* and this change should not be used in those cases.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+ DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst);
uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits();
if (next_insn_idx >= code_item_->insns_size_in_code_units_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";