Use CodeItemAccessor helpers for method verifier
Create a code_item_accessor_ in the verifier and replace the existing
code_item field. Added some handling in DexFile to deal with
try/catch items.
Bug: 63756964
Test: test-art-host
Change-Id: I4e073c9cb29f94518f0016fccbe1628185884df4
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index df75e07..524b0a6 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -20,6 +20,7 @@
#include <memory>
#include "base/logging.h"
+#include "code_item_accessors-inl.h"
#include "dex_file.h"
#include "dex_instruction-inl.h"
#include "runtime.h"
@@ -64,7 +65,7 @@
if (method_verifier->HasFailures()) {
return;
}
- for (const DexInstructionPcPair& pair : method_verifier->CodeItem()->Instructions()) {
+ for (const DexInstructionPcPair& pair : method_verifier->CodeItem()) {
const Instruction& inst = pair.Inst();
const Instruction::Code code = inst.Opcode();
if (code == Instruction::CHECK_CAST) {
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index 595dd4d..2432f13 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -269,7 +269,9 @@
// loop for synchronized blocks.
if (ContainsElement(throwing_blocks_, block)) {
// Try to find a TryItem covering the block.
- const int32_t try_item_idx = DexFile::FindTryItem(code_item_, block->GetDexPc());
+ const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(code_item_, 0u),
+ code_item_.tries_size_,
+ block->GetDexPc());
if (try_item_idx != -1) {
// Block throwing and in a TryItem. Store the try block information.
try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(code_item_, try_item_idx));
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
index 2c5bc2e..d04849d 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/code_item_accessors-inl.h
@@ -21,6 +21,7 @@
#include "art_method-inl.h"
#include "cdex/compact_dex_file.h"
+#include "dex_file-inl.h"
#include "standard_dex_file.h"
namespace art {
@@ -130,6 +131,25 @@
return CreateNullable(method->GetDexFile(), method->GetCodeItem());
}
+inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
+ const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
+ return {
+ try_items,
+ try_items + TriesSize() };
+}
+
+inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
+ return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
+}
+
+inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
+ IterationRange<const DexFile::TryItem*> try_items(TryItems());
+ int32_t index = DexFile::FindTryItem(try_items.begin(),
+ try_items.end() - try_items.begin(),
+ try_dex_pc);
+ return index != -1 ? &try_items.begin()[index] : nullptr;
+}
+
} // namespace art
#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
index fdc8ac5..aa1305a 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/code_item_accessors.h
@@ -50,6 +50,11 @@
return insns_;
}
+ // Return the instruction for a dex pc.
+ const Instruction& InstructionAt(uint32_t dex_pc) const {
+ return *Instruction::At(insns_ + dex_pc);
+ }
+
// Return true if the accessor has a code item.
bool HasCodeItem() const {
return Insns() != nullptr;
@@ -98,12 +103,19 @@
return tries_size_;
}
+ IterationRange<const DexFile::TryItem*> TryItems() const;
+
+ const uint8_t* GetCatchHandlerData(size_t offset = 0) const;
+
+ const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
+
// CreateNullable allows ArtMethods that have a null code item.
ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
- ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(const DexFile* dex_file,
- const DexFile::CodeItem* code_item);
+ ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(
+ const DexFile* dex_file,
+ const DexFile::CodeItem* code_item);
protected:
CodeItemDataAccessor() = default;
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 58cd486..c926a0d 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -135,9 +135,13 @@
}
inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, uint32_t offset) {
- const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_];
+ return GetTryItems(code_item.Instructions().end(), offset);
+}
+
+inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
+ uint32_t offset) {
return reinterpret_cast<const TryItem*>
- (RoundUp(reinterpret_cast<uintptr_t>(insns_end_), 4)) + offset;
+ (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), 4)) + offset;
}
static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 7b0c46b..af79207 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -486,20 +486,18 @@
return Signature(this, *proto_id);
}
-int32_t DexFile::FindTryItem(const CodeItem &code_item, uint32_t address) {
- // Note: Signed type is important for max and min.
- int32_t min = 0;
- int32_t max = code_item.tries_size_ - 1;
+int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
+ uint32_t min = 0;
+ uint32_t max = tries_size;
+ while (min < max) {
+ const uint32_t mid = (min + max) / 2;
- while (min <= max) {
- int32_t mid = min + ((max - min) / 2);
-
- const art::DexFile::TryItem* ti = GetTryItems(code_item, mid);
- uint32_t start = ti->start_addr_;
- uint32_t end = start + ti->insn_count_;
+ const art::DexFile::TryItem& ti = try_items[mid];
+ const uint32_t start = ti.start_addr_;
+ const uint32_t end = start + ti.insn_count_;
if (address < start) {
- max = mid - 1;
+ max = mid;
} else if (address >= end) {
min = mid + 1;
} else { // We have a winner!
@@ -511,12 +509,8 @@
}
int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address) {
- int32_t try_item = FindTryItem(code_item, address);
- if (try_item == -1) {
- return -1;
- } else {
- return DexFile::GetTryItems(code_item, try_item)->handler_off_;
- }
+ int32_t try_item = FindTryItem(GetTryItems(code_item, 0), code_item.tries_size_, address);
+ return (try_item == -1) ? -1 : DexFile::GetTryItems(code_item, try_item)->handler_off_;
}
bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 2c6a430..cdefb23 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -753,17 +753,23 @@
return begin_ + call_site_id.data_off_;
}
+ static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset);
// Get the base of the encoded data for the given DexCode.
- static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+ static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
+ uint32_t tries_size,
+ uint32_t offset) {
const uint8_t* handler_data =
- reinterpret_cast<const uint8_t*>(GetTryItems(code_item, code_item.tries_size_));
+ reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
return handler_data + offset;
}
+ static const uint8_t* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) {
+ return GetCatchHandlerData(code_item.Instructions().end(), code_item.tries_size_, offset);
+ }
// Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
- static int32_t FindTryItem(const CodeItem &code_item, uint32_t address);
+ static int32_t FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address);
// Find the handler offset associated with the given address (ie dex pc). Returns -1 if none.
static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address);
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index 9bb875c..a7fa9f3 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -27,10 +27,6 @@
namespace art {
namespace verifier {
-inline const DexFile::CodeItem* MethodVerifier::CodeItem() const {
- return code_item_;
-}
-
inline RegisterLine* MethodVerifier::GetRegLine(uint32_t dex_pc) {
return reg_table_.GetLine(dex_pc);
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 121f3cf..a75157d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -564,7 +564,7 @@
dex_cache_(dex_cache),
class_loader_(class_loader),
class_def_(class_def),
- code_item_(code_item),
+ code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),
@@ -616,29 +616,21 @@
verifier.FindLocksAtDexPc();
}
-static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) {
- for (const DexInstructionPcPair& inst : code_item->Instructions()) {
- if (inst->Opcode() == Instruction::MONITOR_ENTER) {
- return true;
- }
- }
- return false;
-}
-
void MethodVerifier::FindLocksAtDexPc() {
CHECK(monitor_enter_dex_pcs_ != nullptr);
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
- // Quick check whether there are any monitor_enter instructions at all.
- if (!HasMonitorEnterInstructions(code_item_)) {
- return;
+ // Quick check whether there are any monitor_enter instructions before verifying.
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
+ if (inst->Opcode() == Instruction::MONITOR_ENTER) {
+ // Strictly speaking, we ought to be able to get away with doing a subset of the full method
+ // verification. In practice, the phase we want relies on data structures set up by all the
+ // earlier passes, so we just run the full method verification and bail out early when we've
+ // got what we wanted.
+ Verify();
+ return;
+ }
}
-
- // Strictly speaking, we ought to be able to get away with doing a subset of the full method
- // verification. In practice, the phase we want relies on data structures set up by all the
- // earlier passes, so we just run the full method verification and bail out early when we've
- // got what we wanted.
- Verify();
}
ArtField* MethodVerifier::FindAccessedFieldAtDexPc(ArtMethod* m, uint32_t dex_pc) {
@@ -663,7 +655,7 @@
}
ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -677,7 +669,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+ const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
return GetQuickFieldAccess(inst, register_line);
}
@@ -703,7 +695,7 @@
}
ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) {
- CHECK(code_item_ != nullptr); // This only makes sense for methods with code.
+ CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code.
// Strictly speaking, we ought to be able to get away with doing a subset of the full method
// verification. In practice, the phase we want relies on data structures set up by all the
@@ -717,7 +709,7 @@
if (register_line == nullptr) {
return nullptr;
}
- const Instruction* inst = &code_item_->InstructionAt(dex_pc);
+ const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc);
const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK);
return GetQuickInvokedMethod(inst, register_line, is_range, false);
}
@@ -769,7 +761,7 @@
}
// If there aren't any instructions, make sure that's expected, then exit successfully.
- if (code_item_ == nullptr) {
+ if (!code_item_accessor_.HasCodeItem()) {
// Only native or abstract methods may not have code.
if ((method_access_flags_ & (kAccNative | kAccAbstract)) == 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "zero-length code in concrete non-native method";
@@ -861,17 +853,19 @@
}
// Sanity-check the register counts. ins + locals = registers, so make sure that ins <= registers.
- if (code_item_->ins_size_ > code_item_->registers_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins=" << code_item_->ins_size_
- << " regs=" << code_item_->registers_size_;
+ if (code_item_accessor_.InsSize() > code_item_accessor_.RegistersSize()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad register counts (ins="
+ << code_item_accessor_.InsSize()
+ << " regs=" << code_item_accessor_.RegistersSize();
return false;
}
// Allocate and initialize an array to hold instruction data.
- insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(code_item_->insns_size_in_code_units_));
+ insn_flags_.reset(allocator_.AllocArray<InstructionFlags>(
+ code_item_accessor_.InsnsSizeInCodeUnits()));
DCHECK(insn_flags_ != nullptr);
std::uninitialized_fill_n(insn_flags_.get(),
- code_item_->insns_size_in_code_units_,
+ code_item_accessor_.InsnsSizeInCodeUnits(),
InstructionFlags());
// Run through the instructions and see if the width checks out.
bool result = ComputeWidthsAndCountOps();
@@ -923,7 +917,7 @@
// 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 Instruction& inst = code_item_->InstructionAt(work_insn_idx_);
+ const Instruction& inst = code_item_accessor_.InstructionAt(work_insn_idx_);
int opcode_flags = Instruction::FlagsOf(inst.Opcode());
if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) {
@@ -986,15 +980,14 @@
size_t new_instance_count = 0;
size_t monitor_enter_count = 0;
- IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
// We can't assume the instruction is well formed, handle the case where calculating the size
// goes past the end of the code item.
- SafeDexInstructionIterator it(instructions.begin(), instructions.end());
- for ( ; !it.IsErrorState() && it < instructions.end(); ++it) {
+ SafeDexInstructionIterator it(code_item_accessor_.begin(), code_item_accessor_.end());
+ for ( ; !it.IsErrorState() && it < code_item_accessor_.end(); ++it) {
// In case the instruction goes past the end of the code item, make sure to not process it.
SafeDexInstructionIterator next = it;
++next;
- if (next.IsErrorState() || next > instructions.end()) {
+ if (next.IsErrorState()) {
break;
}
Instruction::Code opcode = it->Opcode();
@@ -1021,8 +1014,8 @@
GetInstructionFlags(it.DexPc()).SetIsOpcode();
}
- if (it != instructions.end()) {
- const size_t insns_size = code_item_->insns_size_in_code_units_;
+ if (it != code_item_accessor_.end()) {
+ const size_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected ("
<< it.DexPc() << " vs. " << insns_size << ")";
return false;
@@ -1034,17 +1027,14 @@
}
bool MethodVerifier::ScanTryCatchBlocks() {
- uint32_t tries_size = code_item_->tries_size_;
+ const uint32_t tries_size = code_item_accessor_.TriesSize();
if (tries_size == 0) {
return true;
}
- uint32_t insns_size = code_item_->insns_size_in_code_units_;
- const DexFile::TryItem* tries = DexFile::GetTryItems(*code_item_, 0);
-
- for (uint32_t idx = 0; idx < tries_size; idx++) {
- const DexFile::TryItem* try_item = &tries[idx];
- uint32_t start = try_item->start_addr_;
- uint32_t end = start + try_item->insn_count_;
+ const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
+ for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) {
+ const uint32_t start = try_item.start_addr_;
+ const uint32_t end = start + try_item.insn_count_;
if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad exception entry: startAddr=" << start
<< " endAddr=" << end << " (size=" << insns_size << ")";
@@ -1055,18 +1045,14 @@
<< "'try' block starts inside an instruction (" << start << ")";
return false;
}
- uint32_t dex_pc = start;
- const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc);
- while (dex_pc < end) {
- GetInstructionFlags(dex_pc).SetInTry();
- size_t insn_size = inst->SizeInCodeUnits();
- dex_pc += insn_size;
- inst = inst->RelativeAt(insn_size);
+ DexInstructionIterator end_it(code_item_accessor_.Insns(), end);
+ for (DexInstructionIterator it(code_item_accessor_.Insns(), start); it < end_it; ++it) {
+ GetInstructionFlags(it.DexPc()).SetInTry();
}
}
// Iterate over each of the handlers to verify target addresses.
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
- uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
+ const uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
ClassLinker* linker = Runtime::Current()->GetClassLinker();
for (uint32_t idx = 0; idx < handlers_size; idx++) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -1077,7 +1063,7 @@
<< "exception handler starts at bad address (" << dex_pc << ")";
return false;
}
- if (!CheckNotMoveResult(code_item_->insns_, dex_pc)) {
+ if (!CheckNotMoveResult(code_item_accessor_.Insns(), dex_pc)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD)
<< "exception handler begins with move-result* (" << dex_pc << ")";
return false;
@@ -1105,7 +1091,7 @@
/* 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();
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const uint32_t dex_pc = inst.DexPc();
if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&inst.Inst(), dex_pc)) {
DCHECK_NE(failures_.size(), 0U);
@@ -1259,18 +1245,18 @@
}
inline bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
- if (UNLIKELY(idx >= code_item_->registers_size_)) {
+ if (UNLIKELY(idx >= code_item_accessor_.RegistersSize())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register index out of range (" << idx << " >= "
- << code_item_->registers_size_ << ")";
+ << code_item_accessor_.RegistersSize() << ")";
return false;
}
return true;
}
inline bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
- if (UNLIKELY(idx + 1 >= code_item_->registers_size_)) {
+ if (UNLIKELY(idx + 1 >= code_item_accessor_.RegistersSize())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register index out of range (" << idx
- << "+1 >= " << code_item_->registers_size_ << ")";
+ << "+1 >= " << code_item_accessor_.RegistersSize() << ")";
return false;
}
return true;
@@ -1387,8 +1373,8 @@
}
bool MethodVerifier::CheckArrayData(uint32_t cur_offset) {
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
const uint16_t* array_data;
int32_t array_data_offset;
@@ -1451,10 +1437,9 @@
<< reinterpret_cast<void*>(cur_offset) << " +" << offset;
return false;
}
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
int32_t abs_offset = cur_offset + offset;
if (UNLIKELY(abs_offset < 0 ||
- (uint32_t) abs_offset >= insn_count ||
+ (uint32_t) abs_offset >= code_item_accessor_.InsnsSizeInCodeUnits() ||
!GetInstructionFlags(abs_offset).IsOpcode())) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> "
<< reinterpret_cast<void*>(abs_offset) << ") at "
@@ -1467,7 +1452,7 @@
bool MethodVerifier::GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
bool* selfOkay) {
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
*pConditional = false;
*selfOkay = false;
switch (*insns & 0xff) {
@@ -1503,9 +1488,9 @@
}
bool MethodVerifier::CheckSwitchTargets(uint32_t cur_offset) {
- const uint32_t insn_count = code_item_->insns_size_in_code_units_;
+ const uint32_t insn_count = code_item_accessor_.InsnsSizeInCodeUnits();
DCHECK_LT(cur_offset, insn_count);
- const uint16_t* insns = code_item_->insns_ + cur_offset;
+ const uint16_t* insns = code_item_accessor_.Insns() + cur_offset;
/* make sure the start of the switch is in range */
int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
if (UNLIKELY(static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
@@ -1610,7 +1595,7 @@
}
bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
- uint16_t registers_size = code_item_->registers_size_;
+ uint16_t registers_size = code_item_accessor_.RegistersSize();
for (uint32_t idx = 0; idx < vA; idx++) {
if (UNLIKELY(arg[idx] >= registers_size)) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index (" << arg[idx]
@@ -1623,7 +1608,7 @@
}
bool MethodVerifier::CheckVarArgRangeRegs(uint32_t vA, uint32_t vC) {
- uint16_t registers_size = code_item_->registers_size_;
+ uint16_t registers_size = code_item_accessor_.RegistersSize();
// vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of
// integer overflow when adding them here.
if (UNLIKELY(vA + vC > registers_size)) {
@@ -1635,13 +1620,12 @@
}
bool MethodVerifier::VerifyCodeFlow() {
- uint16_t registers_size = code_item_->registers_size_;
- uint32_t insns_size = code_item_->insns_size_in_code_units_;
+ const uint16_t registers_size = code_item_accessor_.RegistersSize();
/* Create and initialize table holding register status */
reg_table_.Init(kTrackCompilerInterestPoints,
insn_flags_.get(),
- insns_size,
+ code_item_accessor_.InsnsSizeInCodeUnits(),
registers_size,
this);
@@ -1681,7 +1665,7 @@
}
void MethodVerifier::Dump(VariableIndentationOutputStream* vios) {
- if (code_item_ == nullptr) {
+ if (!code_item_accessor_.HasCodeItem()) {
vios->Stream() << "Native method\n";
return;
}
@@ -1693,7 +1677,7 @@
vios->Stream() << "Dumping instructions and register lines:\n";
ScopedIndentation indent1(vios);
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const size_t dex_pc = inst.DexPc();
RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
if (reg_line != nullptr) {
@@ -1729,10 +1713,10 @@
RegisterLine* reg_line = reg_table_.GetLine(0);
// Should have been verified earlier.
- DCHECK_GE(code_item_->registers_size_, code_item_->ins_size_);
+ DCHECK_GE(code_item_accessor_.RegistersSize(), code_item_accessor_.InsSize());
- uint32_t arg_start = code_item_->registers_size_ - code_item_->ins_size_;
- size_t expected_args = code_item_->ins_size_; /* long/double count as two */
+ uint32_t arg_start = code_item_accessor_.RegistersSize() - code_item_accessor_.InsSize();
+ size_t expected_args = code_item_accessor_.InsSize(); /* long/double count as two */
// Include the "this" pointer.
size_t cur_arg = 0;
@@ -1884,8 +1868,8 @@
}
bool MethodVerifier::CodeFlowVerifyMethod() {
- const uint16_t* insns = code_item_->insns_;
- const uint32_t insns_size = code_item_->insns_size_in_code_units_;
+ const uint16_t* insns = code_item_accessor_.Insns();
+ const uint32_t insns_size = code_item_accessor_.InsnsSizeInCodeUnits();
/* Begin by marking the first instruction as "changed". */
GetInstructionFlags(0).SetChanged();
@@ -1960,7 +1944,7 @@
*/
int dead_start = -1;
- for (const DexInstructionPcPair& inst : code_item_->Instructions()) {
+ for (const DexInstructionPcPair& inst : code_item_accessor_) {
const uint32_t insn_idx = inst.DexPc();
/*
* Switch-statement data doesn't get "visited" by scanner. It
@@ -1989,7 +1973,7 @@
if (dead_start >= 0) {
LogVerifyInfo()
<< "dead code " << reinterpret_cast<void*>(dead_start)
- << "-" << reinterpret_cast<void*>(code_item_->insns_size_in_code_units_ - 1);
+ << "-" << reinterpret_cast<void*>(code_item_accessor_.InsnsSizeInCodeUnits() - 1);
}
// To dump the state of the verify after a method, do something like:
// if (dex_file_->PrettyMethod(dex_method_idx_) ==
@@ -2075,7 +2059,7 @@
*
* The behavior can be determined from the opcode flags.
*/
- const uint16_t* insns = code_item_->insns_ + work_insn_idx_;
+ const uint16_t* insns = code_item_accessor_.Insns() + work_insn_idx_;
const Instruction* inst = Instruction::At(insns);
int opcode_flags = Instruction::FlagsOf(inst->Opcode());
@@ -2375,7 +2359,7 @@
while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) {
prev_idx--;
}
- const Instruction& prev_inst = code_item_->InstructionAt(prev_idx);
+ const Instruction& prev_inst = code_item_accessor_.InstructionAt(prev_idx);
switch (prev_inst.Opcode()) {
case Instruction::MOVE_OBJECT:
case Instruction::MOVE_OBJECT_16:
@@ -2683,7 +2667,7 @@
break;
}
- const Instruction& instance_of_inst = code_item_->InstructionAt(instance_of_idx);
+ const Instruction& instance_of_inst = code_item_accessor_.InstructionAt(instance_of_idx);
/* Check for peep-hole pattern of:
* ...;
@@ -2722,7 +2706,8 @@
(orig_type.IsZero() ||
orig_type.IsStrictlyAssignableFrom(
cast_type.Merge(orig_type, ®_types_, this), this))) {
- RegisterLine* update_line = RegisterLine::Create(code_item_->registers_size_, this);
+ RegisterLine* update_line = RegisterLine::Create(code_item_accessor_.RegistersSize(),
+ this);
if (inst->Opcode() == Instruction::IF_EQZ) {
fallthrough_line.reset(update_line);
} else {
@@ -2745,7 +2730,7 @@
work_insn_idx_)) {
break;
}
- const Instruction& move_inst = code_item_->InstructionAt(move_idx);
+ const Instruction& move_inst = code_item_accessor_.InstructionAt(move_idx);
switch (move_inst.Opcode()) {
case Instruction::MOVE_OBJECT:
if (move_inst.VRegA_12x() == instance_of_inst.VRegB_22c()) {
@@ -3564,7 +3549,8 @@
return false;
}
DCHECK_EQ(isConditional, (opcode_flags & Instruction::kContinue) != 0);
- if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, work_insn_idx_ + branch_target)) {
+ if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(),
+ work_insn_idx_ + branch_target)) {
return false;
}
/* update branch target, set "changed" if appropriate */
@@ -3609,8 +3595,8 @@
offset = switch_insns[offset_to_targets + targ * 2] |
(static_cast<int32_t>(switch_insns[offset_to_targets + targ * 2 + 1]) << 16);
abs_offset = work_insn_idx_ + offset;
- DCHECK_LT(abs_offset, code_item_->insns_size_in_code_units_);
- if (!CheckNotMoveExceptionOrMoveResult(code_item_->insns_, abs_offset)) {
+ DCHECK_LT(abs_offset, code_item_accessor_.InsnsSizeInCodeUnits());
+ if (!CheckNotMoveExceptionOrMoveResult(code_item_accessor_.Insns(), abs_offset)) {
return false;
}
if (!UpdateRegisters(abs_offset, work_line_.get(), false)) {
@@ -3625,7 +3611,9 @@
*/
if ((opcode_flags & Instruction::kThrow) != 0 && GetInstructionFlags(work_insn_idx_).IsInTry()) {
bool has_catch_all_handler = false;
- CatchHandlerIterator iterator(*code_item_, work_insn_idx_);
+ const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(work_insn_idx_);
+ CHECK(try_item != nullptr);
+ CatchHandlerIterator iterator(code_item_accessor_.GetCatchHandlerData(try_item->handler_off_));
// Need the linker to try and resolve the handled class to check if it's Throwable.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -3682,15 +3670,15 @@
* and this change should not be used in those cases.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst);
+ DCHECK_EQ(&code_item_accessor_.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_) {
+ if (next_insn_idx >= code_item_accessor_.InsnsSizeInCodeUnits()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area";
return false;
}
// The only way to get to a move-exception instruction is to get thrown there. Make sure the
// next instruction isn't one.
- if (!CheckNotMoveException(code_item_->insns_, next_insn_idx)) {
+ if (!CheckNotMoveException(code_item_accessor_.Insns(), next_insn_idx)) {
return false;
}
if (nullptr != fallthrough_line) {
@@ -3699,7 +3687,7 @@
}
if (GetInstructionFlags(next_insn_idx).IsReturn()) {
// For returns we only care about the operand to the return, all other registers are dead.
- const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn_idx);
+ const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn_idx);
AdjustReturnLine(this, ret_inst, work_line_.get());
}
RegisterLine* next_line = reg_table_.GetLine(next_insn_idx);
@@ -3731,14 +3719,14 @@
* alone and let the caller sort it out.
*/
if ((opcode_flags & Instruction::kContinue) != 0) {
- DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst);
+ DCHECK_EQ(&code_item_accessor_.InstructionAt(work_insn_idx_), inst);
*start_guess = work_insn_idx_ + inst->SizeInCodeUnits();
} else if ((opcode_flags & Instruction::kBranch) != 0) {
/* we're still okay if branch_target is zero */
*start_guess = work_insn_idx_ + branch_target;
}
- DCHECK_LT(*start_guess, code_item_->insns_size_in_code_units_);
+ DCHECK_LT(*start_guess, code_item_accessor_.InsnsSizeInCodeUnits());
DCHECK(GetInstructionFlags(*start_guess).IsOpcode());
if (have_pending_runtime_throw_failure_) {
@@ -3821,8 +3809,8 @@
const RegType& MethodVerifier::GetCaughtExceptionType() {
const RegType* common_super = nullptr;
- if (code_item_->tries_size_ != 0) {
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0);
+ if (code_item_accessor_.TriesSize() != 0) {
+ const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData();
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t i = 0; i < handlers_size; i++) {
CatchHandlerIterator iterator(handlers_ptr);
@@ -4041,9 +4029,10 @@
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_->outs_size_) {
+ if (expected_args > code_item_accessor_.OutsSize()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ << ") exceeds outsSize ("
+ << code_item_accessor_.OutsSize() << ")";
return nullptr;
}
@@ -4554,9 +4543,9 @@
const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_->outs_size_) {
+ if (expected_args > code_item_accessor_.OutsSize()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ << ") exceeds outsSize (" << code_item_accessor_.OutsSize() << ")";
return nullptr;
}
@@ -5142,8 +5131,7 @@
}
}
-ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
- RegisterLine* reg_line) {
+ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) {
DCHECK(IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) << inst->Opcode();
const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c());
if (!object_type.HasClass()) {
@@ -5330,7 +5318,7 @@
// For returns we only care about the operand to the return, all other registers are dead.
// Initialize them as conflicts so they don't add to GC and deoptimization information.
- const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
+ const Instruction* ret_inst = &code_item_accessor_.InstructionAt(next_insn);
AdjustReturnLine(this, ret_inst, target_line);
// Directly bail if a hard failure was found.
if (have_pending_hard_failure_) {
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 1f1d7c1..813ce87 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -25,6 +25,7 @@
#include "base/macros.h"
#include "base/scoped_arena_containers.h"
#include "base/value_object.h"
+#include "code_item_accessors.h"
#include "dex_file.h"
#include "dex_file_types.h"
#include "handle.h"
@@ -186,7 +187,9 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Accessors used by the compiler via CompilerCallback
- const DexFile::CodeItem* CodeItem() const;
+ const CodeItemDataAccessor& CodeItem() const {
+ return code_item_accessor_;
+ }
RegisterLine* GetRegLine(uint32_t dex_pc);
ALWAYS_INLINE const InstructionFlags& GetInstructionFlags(size_t index) const;
ALWAYS_INLINE InstructionFlags& GetInstructionFlags(size_t index);
@@ -738,7 +741,7 @@
// The class loader for the declaring class of the method.
Handle<mirror::ClassLoader> class_loader_ GUARDED_BY(Locks::mutator_lock_);
const DexFile::ClassDef& class_def_; // The class def of the declaring class of the method.
- const DexFile::CodeItem* const code_item_; // The code item containing the code for the method.
+ const CodeItemDataAccessor code_item_accessor_;
const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class.
// Instruction widths and flags, one entry per code unit.
// Owned, but not unique_ptr since insn_flags_ are allocated in arenas.