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, &reg_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.