Make CodeItem fields private

Make code item fields private and use accessors. Added a hand full of
friend classes to reduce the size of the change.

Changed default to be nullable and removed CreateNullable.
CreateNullable was a bad API since it defaulted to the unsafe, may
add a CreateNonNullable if it's important for performance.

Motivation:
Have a different layout for code items in cdex.

Bug: 63756964
Test: test-art-host-gtest
Test: test/testrunner/testrunner.py --host
Test: art/tools/run-jdwp-tests.sh '--mode=host' '--variant=X32' --debug

Change-Id: I42bc7435e20358682075cb6de52713b595f95bf9
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 869394c..c6c4f4a 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -459,16 +459,8 @@
   }
 }
 
-inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() {
-  CodeItemInstructionAccessor accessor(this);
-  return { accessor.begin(),
-           accessor.end() };
-}
-
-inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() {
-  CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this));
-  return { accessor.begin(),
-           accessor.end() };
+inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
+  return CodeItemInstructionAccessor(this);
 }
 
 }  // namespace art
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9005120..7ddaa7e 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -297,9 +297,8 @@
     }
   }
   if (found_dex_pc != dex::kDexNoIndex) {
-    const Instruction* first_catch_instr =
-        Instruction::At(&code_item->insns_[found_dex_pc]);
-    *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
+    const Instruction& first_catch_instr = DexInstructions().InstructionAt(found_dex_pc);
+    *has_no_move_exception = (first_catch_instr.Opcode() != Instruction::MOVE_EXCEPTION);
   }
   // Put the exception back.
   if (exception != nullptr) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index f433223..ab90a10 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -27,6 +27,7 @@
 #include "base/iteration_range.h"
 #include "base/macros.h"
 #include "base/runtime_debug.h"
+#include "code_item_accessors.h"
 #include "dex_file.h"
 #include "dex_instruction_iterator.h"
 #include "gc_root.h"
@@ -716,13 +717,9 @@
             "ptr_sized_fields_.entry_point_from_quick_compiled_code_");
   }
 
-  // Returns the dex instructions of the code item for the art method. Must not be called on null
-  // code items.
-  ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions()
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Handles a null code item by returning iterators that have a null address.
-  ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions()
+  // Returns the dex instructions of the code item for the art method. Returns an empty array for
+  // the null code item case.
+  ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions()
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  protected:
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index d9e8915..c4a613a 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
 
 #include "art_method-inl.h"
+#include "code_item_accessors-inl.h"
 #include "dex_file_types.h"
 #include "oat_quick_method_header.h"
 #include "scoped_thread_state_change-inl.h"
@@ -66,14 +67,15 @@
     CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo();
     CodeInfoEncoding encoding = code_info.ExtractEncoding();
     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
-    uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
+    CodeItemDataAccessor accessor(m);
+    uint16_t number_of_dex_registers = accessor.RegistersSize();
     DexRegisterMap dex_register_map =
         code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
     uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
     BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
     for (int i = 0; i < number_of_references; ++i) {
       int reg = registers[i];
-      CHECK(reg < m->GetCodeItem()->registers_size_);
+      CHECK_LT(reg, accessor.RegistersSize());
       DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(
           reg, number_of_dex_registers, code_info, encoding);
       switch (location.GetKind()) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 55fa632..45b7618 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4317,15 +4317,14 @@
 
 void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) {
   // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
-  const DexFile::CodeItem* code_item =
-      method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset());
-  if (code_item == nullptr) {
+  CodeItemDataAccessor accessor(method);
+  if (!accessor.HasCodeItem()) {
     return;  // native or abstract method
   }
-  if (code_item->tries_size_ == 0) {
+  if (accessor.TriesSize() == 0) {
     return;  // nothing to process
   }
-  const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+  const uint8_t* handlers_ptr = accessor.GetCatchHandlerData(0);
   uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
   for (uint32_t idx = 0; idx < handlers_size; idx++) {
     CatchHandlerIterator iterator(handlers_ptr);
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
index 1ba3c55..f63ea69 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/code_item_accessors-inl.h
@@ -30,27 +30,9 @@
 inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
     : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
 
-inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable(
-    ArtMethod* method) {
-  DCHECK(method != nullptr);
-  CodeItemInstructionAccessor ret;
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
-  if (code_item != nullptr) {
-    ret.Init(method->GetDexFile(), code_item);
-  } else {
-    DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
-  }
-  return ret;
-}
-
 inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
     : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
 
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
-  DCHECK(method != nullptr);
-  return CreateNullable(method->GetDexFile(), method->GetCodeItem());
-}
-
 inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
     : CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {}
 
@@ -59,7 +41,7 @@
   if (code_item == nullptr) {
     return;
   }
-  Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item));
+  Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item->debug_info_off_));
 }
 
 }  // namespace art
diff --git a/runtime/code_item_accessors-no_art-inl.h b/runtime/code_item_accessors-no_art-inl.h
index 96321b5..ebdd78b 100644
--- a/runtime/code_item_accessors-no_art-inl.h
+++ b/runtime/code_item_accessors-no_art-inl.h
@@ -24,7 +24,6 @@
 #include "standard_dex_file.h"
 
 // The no ART version is used by binaries that don't include the whole runtime.
-
 namespace art {
 
 inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
@@ -39,13 +38,14 @@
 
 inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
                                               const DexFile::CodeItem* code_item) {
-  DCHECK(dex_file != nullptr);
-  DCHECK(code_item != nullptr);
-  if (dex_file->IsCompactDexFile()) {
-    Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
-  } else {
-    DCHECK(dex_file->IsStandardDexFile());
-    Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+  if (code_item != nullptr) {
+    DCHECK(dex_file != nullptr);
+    if (dex_file->IsCompactDexFile()) {
+      Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+    } else {
+      DCHECK(dex_file->IsStandardDexFile());
+      Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+    }
   }
 }
 
@@ -63,6 +63,14 @@
   return DexInstructionIterator(insns_, insns_size_in_code_units_);
 }
 
+inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
+    uint32_t start_dex_pc) const {
+  DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
+  return {
+      DexInstructionIterator(insns_, start_dex_pc),
+      DexInstructionIterator(insns_, insns_size_in_code_units_) };
+}
+
 inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
   CodeItemInstructionAccessor::Init(code_item);
   registers_size_ = code_item.registers_size_;
@@ -81,13 +89,14 @@
 
 inline void CodeItemDataAccessor::Init(const DexFile* dex_file,
                                        const DexFile::CodeItem* code_item) {
-  DCHECK(dex_file != nullptr);
-  DCHECK(code_item != nullptr);
-  if (dex_file->IsCompactDexFile()) {
-    CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
-  } else {
-    DCHECK(dex_file->IsStandardDexFile());
-    CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+  if (code_item != nullptr) {
+    DCHECK(dex_file != nullptr);
+    if (dex_file->IsCompactDexFile()) {
+      CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+    } else {
+      DCHECK(dex_file->IsStandardDexFile());
+      CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+    }
   }
 }
 
@@ -96,18 +105,6 @@
   Init(dex_file, code_item);
 }
 
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(
-    const DexFile* dex_file,
-    const DexFile::CodeItem* code_item) {
-  CodeItemDataAccessor ret;
-  if (code_item != nullptr) {
-    ret.Init(dex_file, code_item);
-  } else {
-    DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
-  }
-  return ret;
-}
-
 inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
   const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
   return {
@@ -163,7 +160,6 @@
                                          context);
 }
 
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
index 9f40114..4cbe7a1 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/code_item_accessors.h
@@ -42,6 +42,8 @@
 
   ALWAYS_INLINE DexInstructionIterator end() const;
 
+  IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const;
+
   uint32_t InsnsSizeInCodeUnits() const {
     return insns_size_in_code_units_;
   }
@@ -52,6 +54,7 @@
 
   // Return the instruction for a dex pc.
   const Instruction& InstructionAt(uint32_t dex_pc) const {
+    DCHECK_LT(dex_pc, InsnsSizeInCodeUnits());
     return *Instruction::At(insns_ + dex_pc);
   }
 
@@ -60,10 +63,6 @@
     return Insns() != nullptr;
   }
 
-  // CreateNullable allows ArtMethods that have a null code item.
-  ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
  protected:
   CodeItemInstructionAccessor() = default;
 
@@ -109,14 +108,6 @@
 
   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);
-
  protected:
   CodeItemDataAccessor() = default;
 
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 267735f..8988702 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "class_linker.h"
+#include "code_item_accessors.h"
 #include "handle_scope-inl.h"
 #include "instrumentation.h"
 #include "interpreter/shadow_frame.h"
@@ -52,7 +53,7 @@
 }  // namespace interpreter
 
 inline void PerformCall(Thread* self,
-                        const DexFile::CodeItem* code_item,
+                        const CodeItemDataAccessor& accessor,
                         ArtMethod* caller_method,
                         const size_t first_dest_reg,
                         ShadowFrame* callee_frame,
@@ -61,13 +62,13 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (LIKELY(Runtime::Current()->IsStarted())) {
     if (use_interpreter_entrypoint) {
-      interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
+      interpreter::ArtInterpreterToInterpreterBridge(self, accessor, callee_frame, result);
     } else {
       interpreter::ArtInterpreterToCompiledCodeBridge(
           self, caller_method, callee_frame, first_dest_reg, result);
     }
   } else {
-    interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
+    interpreter::UnstartedRuntime::Invoke(self, accessor, callee_frame, result, first_dest_reg);
   }
 }
 
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 575d18e..707885c 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -551,43 +551,43 @@
 void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
   uint32_t throw_dex_pc;
   ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc);
-  const DexFile::CodeItem* code = method->GetCodeItem();
-  CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
-  const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
-  if (check_address && !IsValidImplicitCheck(addr, *instr)) {
+  CodeItemInstructionAccessor accessor(method);
+  CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits());
+  const Instruction& instr = accessor.InstructionAt(throw_dex_pc);
+  if (check_address && !IsValidImplicitCheck(addr, instr)) {
     const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
     LOG(FATAL) << "Invalid address for an implicit NullPointerException check: "
                << "0x" << std::hex << addr << std::dec
                << ", at "
-               << instr->DumpString(dex_file)
+               << instr.DumpString(dex_file)
                << " in "
                << method->PrettyMethod();
   }
 
-  switch (instr->Opcode()) {
+  switch (instr.Opcode()) {
     case Instruction::INVOKE_DIRECT:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kDirect);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kDirect);
       break;
     case Instruction::INVOKE_DIRECT_RANGE:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kDirect);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kDirect);
       break;
     case Instruction::INVOKE_VIRTUAL:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kVirtual);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kVirtual);
       break;
     case Instruction::INVOKE_VIRTUAL_RANGE:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kVirtual);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kVirtual);
       break;
     case Instruction::INVOKE_INTERFACE:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kInterface);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kInterface);
       break;
     case Instruction::INVOKE_INTERFACE_RANGE:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kInterface);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kInterface);
       break;
     case Instruction::INVOKE_POLYMORPHIC:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_45cc(), kVirtual);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_45cc(), kVirtual);
       break;
     case Instruction::INVOKE_POLYMORPHIC_RANGE:
-      ThrowNullPointerExceptionForMethodAccess(instr->VRegB_4rcc(), kVirtual);
+      ThrowNullPointerExceptionForMethodAccess(instr.VRegB_4rcc(), kVirtual);
       break;
     case Instruction::INVOKE_VIRTUAL_QUICK:
     case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -612,7 +612,7 @@
     case Instruction::IGET_CHAR:
     case Instruction::IGET_SHORT: {
       ArtField* field =
-          Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+          Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
       ThrowNullPointerExceptionForFieldAccess(field, true /* read */);
       break;
     }
@@ -644,7 +644,7 @@
     case Instruction::IPUT_CHAR:
     case Instruction::IPUT_SHORT: {
       ArtField* field =
-          Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+          Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
       ThrowNullPointerExceptionForFieldAccess(field, false /* write */);
       break;
     }
@@ -707,7 +707,7 @@
       const DexFile* dex_file =
           method->GetDeclaringClass()->GetDexCache()->GetDexFile();
       LOG(FATAL) << "NullPointerException at an unexpected instruction: "
-                 << instr->DumpString(dex_file)
+                 << instr.DumpString(dex_file)
                  << " in "
                  << method->PrettyMethod();
       break;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index c85c233..2be00f5 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -278,11 +278,8 @@
   }
 
  private:
-  static bool IsReturn(ArtMethod* method, uint32_t dex_pc)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    const DexFile::CodeItem* code_item = method->GetCodeItem();
-    const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]);
-    return instruction->IsReturn();
+  static bool IsReturn(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) {
+    return method->DexInstructions().InstructionAt(dex_pc).IsReturn();
   }
 
   static bool IsListeningToDexPcMoved() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1535,15 +1532,15 @@
  */
 static uint16_t MangleSlot(uint16_t slot, ArtMethod* m)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor accessor(m);
+  if (!accessor.HasCodeItem()) {
     // We should not get here for a method without code (native, proxy or abstract). Log it and
     // return the slot as is since all registers are arguments.
     LOG(WARNING) << "Trying to mangle slot for method without code " << m->PrettyMethod();
     return slot;
   }
-  uint16_t ins_size = code_item->ins_size_;
-  uint16_t locals_size = code_item->registers_size_ - ins_size;
+  uint16_t ins_size = accessor.InsSize();
+  uint16_t locals_size = accessor.RegistersSize() - ins_size;
   if (slot >= locals_size) {
     return slot - locals_size;
   } else {
@@ -1566,8 +1563,8 @@
  */
 static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor accessor(m);
+  if (!accessor.HasCodeItem()) {
     // We should not get here for a method without code (native, proxy or abstract). Log it and
     // return the slot as is since all registers are arguments.
     LOG(WARNING) << "Trying to demangle slot for method without code "
@@ -1578,9 +1575,9 @@
       return slot;
     }
   } else {
-    if (slot < code_item->registers_size_) {
-      uint16_t ins_size = code_item->ins_size_;
-      uint16_t locals_size = code_item->registers_size_ - ins_size;
+    if (slot < accessor.RegistersSize()) {
+      uint16_t ins_size = accessor.InsSize();
+      uint16_t locals_size = accessor.RegistersSize() - ins_size;
       *error = JDWP::ERR_NONE;
       return (slot < ins_size) ? slot + locals_size : slot - ins_size;
     }
@@ -1793,9 +1790,9 @@
   if (m == nullptr) {
     return JDWP::ERR_INVALID_METHODID;
   }
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  size_t byte_count = code_item->insns_size_in_code_units_ * 2;
-  const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
+  CodeItemDataAccessor accessor(m);
+  size_t byte_count = accessor.InsnsSizeInCodeUnits() * 2;
+  const uint8_t* begin = reinterpret_cast<const uint8_t*>(accessor.Insns());
   const uint8_t* end = begin + byte_count;
   for (const uint8_t* p = begin; p != end; ++p) {
     bytecodes->push_back(*p);
@@ -2978,9 +2975,8 @@
   Handle<mirror::Throwable> pending_exception(hs.NewHandle(self->GetException()));
   self->ClearException();
   if (kIsDebugBuild && pending_exception != nullptr) {
-    const DexFile::CodeItem* code_item = location.method->GetCodeItem();
-    const Instruction* instr = Instruction::At(&code_item->insns_[location.dex_pc]);
-    CHECK_EQ(Instruction::MOVE_EXCEPTION, instr->Opcode());
+    const Instruction& instr = location.method->DexInstructions().InstructionAt(location.dex_pc);
+    CHECK_EQ(Instruction::MOVE_EXCEPTION, instr.Opcode());
   }
 
   gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 76110f2..f3a88f7 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -320,6 +320,7 @@
       debug_info_off_ = new_offset;
     }
 
+   private:
     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
@@ -340,6 +341,14 @@
     uint16_t insns_[1];                  // actual array of bytecode.
 
    private:
+    ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+    friend class CatchHandlerIterator;
+    friend class CodeItemDataAccessor;
+    friend class CodeItemDebugInfoAccessor;
+    friend class CodeItemInstructionAccessor;
+    friend class DexFile;  // TODO: Remove this one when it's cleaned up.
+    friend class DexFileVerifier;
+    friend class VdexFile;  // TODO: Remove this one when it's cleaned up.
     DISALLOW_COPY_AND_ASSIGN(CodeItem);
   };
 
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 6905504..87eec57 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -22,6 +22,7 @@
 
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
+#include "code_item_accessors-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
 #include "dex_file_loader.h"
@@ -730,15 +731,8 @@
       kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
   const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
-  uint32_t debug_info_offset = raw->GetDebugInfoOffset(code_item);
-  ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item->registers_size_,
-                                        code_item->ins_size_,
-                                        code_item->insns_size_in_code_units_,
-                                        debug_info_offset,
-                                        true,
-                                        1,
-                                        Callback,
-                                        nullptr));
+  CodeItemDebugInfoAccessor accessor(raw.get(), code_item);
+  ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
 }
 
 }  // namespace art
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
index 4de4376..c157ddc 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -30,6 +30,7 @@
 #endif
 #include "base/memory_tool.h"
 
+#include "code_item_accessors-inl.h"
 #include "dex_file-inl.h"
 
 namespace art {
@@ -184,9 +185,12 @@
         if (code_item != nullptr) {
           const void* code_item_begin = reinterpret_cast<const void*>(code_item);
           size_t code_item_start = reinterpret_cast<size_t>(code_item);
-          size_t code_item_start_end = reinterpret_cast<size_t>(&code_item->insns_[1]);
+          CodeItemInstructionAccessor accessor(dex_file_, code_item);
+          size_t code_item_start_end = reinterpret_cast<size_t>(accessor.Insns());
           size_t code_item_start_size = code_item_start_end - code_item_start;
-          range_values_.push_back(std::make_tuple(code_item_begin, code_item_start_size, should_poison));
+          range_values_.push_back(std::make_tuple(code_item_begin,
+                                                  code_item_start_size,
+                                                  should_poison));
         }
         cdit.Next();
       }
@@ -204,9 +208,10 @@
       while (cdit.HasNextMethod()) {
         const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
         if (code_item != nullptr) {
-          const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
+          CodeItemInstructionAccessor accessor(dex_file_, code_item);
+          const void* insns_begin = reinterpret_cast<const void*>(accessor.Insns());
           // Member insns_size_in_code_units_ is in 2-byte units
-          size_t insns_size = code_item->insns_size_in_code_units_ * 2;
+          size_t insns_size = accessor.InsnsSizeInCodeUnits() * 2;
           range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
         }
         cdit.Next();
diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
index d4bc1c7..d22f180 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -28,7 +28,7 @@
                                               ArtMethod* method, Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  const uint16_t* const insns = method->GetCodeItem()->insns_;
+  const uint16_t* const insns = method->DexInstructions().Insns();
   const Instruction::ArrayDataPayload* payload =
       reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset);
   bool success = FillArrayData(array, payload);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index ca5b799..a4d14ec 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -784,8 +784,8 @@
   DCHECK(!method->IsNative()) << method->PrettyMethod();
   uint32_t shorty_len = 0;
   ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-  const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem();
-  DCHECK(code_item != nullptr) << method->PrettyMethod();
+  DCHECK(non_proxy_method->GetCodeItem() != nullptr) << method->PrettyMethod();
+  CodeItemDataAccessor accessor(non_proxy_method);
   const char* shorty = non_proxy_method->GetShorty(&shorty_len);
 
   JValue result;
@@ -795,12 +795,12 @@
   } else {
     const char* old_cause = self->StartAssertNoThreadSuspension(
         "Building interpreter shadow frame");
-    uint16_t num_regs = code_item->registers_size_;
+    uint16_t num_regs = accessor.RegistersSize();
     // No last shadow coming from quick.
     ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
         CREATE_SHADOW_FRAME(num_regs, /* link */ nullptr, method, /* dex pc */ 0);
     ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get();
-    size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
+    size_t first_arg_reg = accessor.RegistersSize() - accessor.InsSize();
     BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
                                                       shadow_frame, first_arg_reg);
     shadow_frame_builder.VisitArguments();
@@ -823,7 +823,7 @@
       }
     }
 
-    result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);
+    result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame);
   }
 
   // Pop transition.
@@ -1121,10 +1121,9 @@
     // code.
     if (!found_stack_map || kIsDebugBuild) {
       uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
-      const DexFile::CodeItem* code;
-      code = caller->GetCodeItem();
-      CHECK_LT(dex_pc, code->insns_size_in_code_units_);
-      const Instruction& instr = code->InstructionAt(dex_pc);
+      CodeItemInstructionAccessor accessor(caller);
+      CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
+      const Instruction& instr = accessor.InstructionAt(dex_pc);
       Instruction::Code instr_code = instr.Opcode();
       bool is_range;
       switch (instr_code) {
@@ -2450,9 +2449,7 @@
     // Fetch the dex_method_idx of the target interface method from the caller.
     uint32_t dex_method_idx;
     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 = code_item->InstructionAt(dex_pc);
+    const Instruction& instr = caller_method->DexInstructions().InstructionAt(dex_pc);
     Instruction::Code instr_code = instr.Opcode();
     DCHECK(instr_code == Instruction::INVOKE_INTERFACE ||
            instr_code == Instruction::INVOKE_INTERFACE_RANGE)
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 49f2021..a4ee21d 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1246,18 +1246,17 @@
         shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
         return false;
       }
-      const DexFile::CodeItem* code_item = m->GetCodeItem();
-      const Instruction* instr = Instruction::At(&code_item->insns_[GetDexPc()]);
-      if (instr->IsInvoke()) {
+      const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
+      if (instr.IsInvoke()) {
         const DexFile* dex_file = m->GetDexFile();
-        if (interpreter::IsStringInit(dex_file, instr->VRegB())) {
+        if (interpreter::IsStringInit(dex_file, instr.VRegB())) {
           // Invoking string init constructor is turned into invoking
           // StringFactory.newStringFromChars() which returns a string.
           shorty = 'L';
           return false;
         }
         // A regular invoke, use callee's shorty.
-        uint32_t method_idx = instr->VRegB();
+        uint32_t method_idx = instr.VRegB();
         shorty = dex_file->GetMethodShorty(method_idx)[0];
       }
       // Stop stack walking since we've seen a Java frame.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 01b7d4e..9b81819 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -240,7 +240,7 @@
 
 static inline JValue Execute(
     Thread* self,
-    const DexFile::CodeItem* code_item,
+    const CodeItemDataAccessor& accessor,
     ShadowFrame& shadow_frame,
     JValue result_register,
     bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -254,11 +254,13 @@
     ArtMethod *method = shadow_frame.GetMethod();
 
     if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
-      instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                        method, 0);
+      instrumentation->MethodEnterEvent(self,
+                                        shadow_frame.GetThisObject(accessor.InsSize()),
+                                        method,
+                                        0);
       if (UNLIKELY(self->IsExceptionPending())) {
         instrumentation->MethodUnwindEvent(self,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            method,
                                            0);
         return JValue();
@@ -277,7 +279,7 @@
           // Calculate the offset of the first input reg. The input registers are in the high regs.
           // It's ok to access the code item here since JIT code will have been touched by the
           // interpreter and compiler already.
-          uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_;
+          uint16_t arg_offset = accessor.RegistersSize() - accessor.InsSize();
           ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result);
           // Push the shadow frame back as the caller will expect it.
           self->PushShadowFrame(&shadow_frame);
@@ -302,27 +304,27 @@
     if (kInterpreterImplKind == kMterpImplKind) {
       if (transaction_active) {
         // No Mterp variant - just use the switch interpreter.
-        return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
                                               false);
       } else if (UNLIKELY(!Runtime::Current()->IsStarted())) {
-        return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
                                                false);
       } else {
         while (true) {
           // Mterp does not support all instrumentation/debugging.
           if (MterpShouldSwitchInterpreters() != 0) {
-            return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+            return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
                                                    false);
           }
           bool returned = ExecuteMterpImpl(self,
-                                           code_item->insns_,
+                                           accessor.Insns(),
                                            &shadow_frame,
                                            &result_register);
           if (returned) {
             return result_register;
           } else {
             // Mterp didn't like that instruction.  Single-step it with the reference interpreter.
-            result_register = ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame,
+            result_register = ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame,
                                                               result_register, true);
             if (shadow_frame.GetDexPC() == dex::kDexNoIndex) {
               // Single-stepped a return or an exception not handled locally.  Return to caller.
@@ -334,10 +336,10 @@
     } else {
       DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
       if (transaction_active) {
-        return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
                                               false);
       } else {
-        return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
                                                false);
       }
     }
@@ -346,19 +348,19 @@
     if (kInterpreterImplKind == kMterpImplKind) {
       // No access check variants for Mterp.  Just use the switch version.
       if (transaction_active) {
-        return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
                                              false);
       } else {
-        return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
                                               false);
       }
     } else {
       DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
       if (transaction_active) {
-        return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
                                              false);
       } else {
-        return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+        return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
                                               false);
       }
     }
@@ -387,12 +389,12 @@
   }
 
   const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");
-  const DexFile::CodeItem* code_item = method->GetCodeItem();
+  CodeItemDataAccessor accessor(method);
   uint16_t num_regs;
   uint16_t num_ins;
-  if (code_item != nullptr) {
-    num_regs =  code_item->registers_size_;
-    num_ins = code_item->ins_size_;
+  if (accessor.HasCodeItem()) {
+    num_regs =  accessor.RegistersSize();
+    num_ins = accessor.InsSize();
   } else if (!method->IsInvokable()) {
     self->EndAssertNoThreadSuspension(old_cause);
     method->ThrowInvocationTimeError();
@@ -454,7 +456,7 @@
     }
   }
   if (LIKELY(!method->IsNative())) {
-    JValue r = Execute(self, code_item, *shadow_frame, JValue(), stay_in_interpreter);
+    JValue r = Execute(self, accessor, *shadow_frame, JValue(), stay_in_interpreter);
     if (result != nullptr) {
       *result = r;
     }
@@ -497,7 +499,7 @@
     DCHECK(!shadow_frame->GetMethod()->MustCountLocks());
 
     self->SetTopOfShadowStack(shadow_frame);
-    const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem();
+    CodeItemDataAccessor accessor(shadow_frame->GetMethod());
     const uint32_t dex_pc = shadow_frame->GetDexPC();
     uint32_t new_dex_pc = dex_pc;
     if (UNLIKELY(self->IsExceptionPending())) {
@@ -510,7 +512,7 @@
           self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex;
     } else if (!from_code) {
       // Deoptimization is not called from code directly.
-      const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
+      const Instruction* instr = &accessor.InstructionAt(dex_pc);
       if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) {
         DCHECK(first);
         // Need to re-execute the dex instruction.
@@ -566,7 +568,7 @@
     }
     if (new_dex_pc != dex::kDexNoIndex) {
       shadow_frame->SetDexPC(new_dex_pc);
-      value = Execute(self, code_item, *shadow_frame, value);
+      value = Execute(self, accessor, *shadow_frame, value);
     }
     ShadowFrame* old_frame = shadow_frame;
     shadow_frame = shadow_frame->GetLink();
@@ -580,7 +582,7 @@
   ret_val->SetJ(value.GetJ());
 }
 
-JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor,
                                       ShadowFrame* shadow_frame) {
   DCHECK_EQ(self, Thread::Current());
   bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -593,11 +595,11 @@
   if (jit != nullptr) {
     jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod());
   }
-  return Execute(self, code_item, *shadow_frame, JValue());
+  return Execute(self, accessor, *shadow_frame, JValue());
 }
 
 void ArtInterpreterToInterpreterBridge(Thread* self,
-                                       const DexFile::CodeItem* code_item,
+                                       const CodeItemDataAccessor& accessor,
                                        ShadowFrame* shadow_frame,
                                        JValue* result) {
   bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -626,7 +628,7 @@
   }
 
   if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
-    result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ());
+    result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ());
   } else {
     // We don't expect to be asked to interpret native code (which is entered via a JNI compiler
     // generated stub) except during testing and image writing.
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index df8568e..f9d7774 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -27,6 +27,7 @@
 }  // namespace mirror
 
 class ArtMethod;
+class CodeItemDataAccessor;
 union JValue;
 class ShadowFrame;
 class Thread;
@@ -52,12 +53,15 @@
                                            DeoptimizationMethodType method_type)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+extern JValue EnterInterpreterFromEntryPoint(Thread* self,
+                                             const CodeItemDataAccessor& accessor,
                                              ShadowFrame* shadow_frame)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-void ArtInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
-                                       ShadowFrame* shadow_frame, JValue* result)
+void ArtInterpreterToInterpreterBridge(Thread* self,
+                                       const CodeItemDataAccessor& accessor,
+                                       ShadowFrame* shadow_frame,
+                                       JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // One-time sanity check.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 122d1a8..deed16b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1320,7 +1320,7 @@
   }
 
   // Compute method information.
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+  CodeItemDataAccessor accessor(called_method);
   // Number of registers for the callee's call frame.
   uint16_t num_regs;
   // Test whether to use the interpreter or compiler entrypoint, and save that result to pass to
@@ -1334,7 +1334,7 @@
       ClassLinker::ShouldUseInterpreterEntrypoint(
           called_method,
           called_method->GetEntryPointFromQuickCompiledCode());
-  if (LIKELY(code_item != nullptr)) {
+  if (LIKELY(accessor.HasCodeItem())) {
     // When transitioning to compiled code, space only needs to be reserved for the input registers.
     // The rest of the frame gets discarded. This also prevents accessing the called method's code
     // item, saving memory by keeping code items of compiled code untouched.
@@ -1342,8 +1342,8 @@
       DCHECK(!Runtime::Current()->IsAotCompiler()) << "Compiler should use interpreter entrypoint";
       num_regs = number_of_inputs;
     } else {
-      num_regs = code_item->registers_size_;
-      DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
+      num_regs = accessor.RegistersSize();
+      DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, accessor.InsSize());
     }
   } else {
     DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
@@ -1367,7 +1367,7 @@
     DCHECK_GT(num_regs, 0u);  // As the method is an instance method, there should be at least 1.
 
     // The new StringFactory call is static and has one fewer argument.
-    if (code_item == nullptr) {
+    if (!accessor.HasCodeItem()) {
       DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
       num_regs--;
     }  // else ... don't need to change num_regs since it comes up from the string_init's code item
@@ -1499,7 +1499,7 @@
   }
 
   PerformCall(self,
-              code_item,
+              accessor,
               shadow_frame.GetMethod(),
               first_dest_reg,
               new_shadow_frame,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 094f086..81c1e1d 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -67,7 +67,7 @@
   {                                                                                             \
     if (UNLIKELY(instrumentation->HasDexPcListeners()) &&                                       \
         UNLIKELY(!DoDexPcMoveEvent(self,                                                        \
-                                   code_item,                                                   \
+                                   accessor,                                                    \
                                    shadow_frame,                                                \
                                    dex_pc,                                                      \
                                    instrumentation,                                             \
@@ -125,7 +125,7 @@
 // jvmti-agents while handling breakpoint or single step events. We had to move this into its own
 // function because it was making ExecuteSwitchImpl have too large a stack.
 NO_INLINE static bool DoDexPcMoveEvent(Thread* self,
-                                       const DexFile::CodeItem* code_item,
+                                       const CodeItemDataAccessor& accessor,
                                        const ShadowFrame& shadow_frame,
                                        uint32_t dex_pc,
                                        const instrumentation::Instrumentation* instrumentation,
@@ -139,7 +139,7 @@
       hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot()));
   self->ClearException();
   instrumentation->DexPcMovedEvent(self,
-                                   shadow_frame.GetThisObject(code_item->ins_size_),
+                                   shadow_frame.GetThisObject(accessor.InsSize()),
                                    shadow_frame.GetMethod(),
                                    dex_pc);
   if (UNLIKELY(self->IsExceptionPending())) {
@@ -188,7 +188,7 @@
 }
 
 template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
                          ShadowFrame& shadow_frame, JValue result_register,
                          bool interpret_one_instruction) {
   constexpr bool do_assignability_check = do_access_check;
@@ -200,10 +200,10 @@
 
   uint32_t dex_pc = shadow_frame.GetDexPC();
   const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
-  const uint16_t* const insns = code_item->insns_;
+  ArtMethod* method = shadow_frame.GetMethod();
+  const uint16_t* const insns = accessor.Insns();
   const Instruction* inst = Instruction::At(insns + dex_pc);
   uint16_t inst_data;
-  ArtMethod* method = shadow_frame.GetMethod();
   jit::Jit* jit = Runtime::Current()->GetJit();
 
   do {
@@ -303,7 +303,7 @@
                      !SendMethodExitEvents(self,
                                            instrumentation,
                                            shadow_frame,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            shadow_frame.GetMethod(),
                                            inst->GetDexPc(insns),
                                            result))) {
@@ -325,7 +325,7 @@
                      !SendMethodExitEvents(self,
                                            instrumentation,
                                            shadow_frame,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            shadow_frame.GetMethod(),
                                            inst->GetDexPc(insns),
                                            result))) {
@@ -348,7 +348,7 @@
                      !SendMethodExitEvents(self,
                                            instrumentation,
                                            shadow_frame,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            shadow_frame.GetMethod(),
                                            inst->GetDexPc(insns),
                                            result))) {
@@ -370,7 +370,7 @@
                      !SendMethodExitEvents(self,
                                            instrumentation,
                                            shadow_frame,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            shadow_frame.GetMethod(),
                                            inst->GetDexPc(insns),
                                            result))) {
@@ -412,7 +412,7 @@
                      !SendMethodExitEvents(self,
                                            instrumentation,
                                            shadow_frame,
-                                           shadow_frame.GetThisObject(code_item->ins_size_),
+                                           shadow_frame.GetThisObject(accessor.InsSize()),
                                            shadow_frame.GetMethod(),
                                            inst->GetDexPc(insns),
                                            result))) {
@@ -2484,19 +2484,19 @@
 
 // Explicit definitions of ExecuteSwitchImpl.
 template HOT_ATTR
-JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, false>(Thread* self, const CodeItemDataAccessor& accessor,
                                       ShadowFrame& shadow_frame, JValue result_register,
                                       bool interpret_one_instruction);
 template HOT_ATTR
-JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, false>(Thread* self, const CodeItemDataAccessor& accessor,
                                        ShadowFrame& shadow_frame, JValue result_register,
                                        bool interpret_one_instruction);
 template
-JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, true>(Thread* self, const CodeItemDataAccessor& accessor,
                                      ShadowFrame& shadow_frame, JValue result_register,
                                      bool interpret_one_instruction);
 template
-JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, true>(Thread* self, const CodeItemDataAccessor& accessor,
                                       ShadowFrame& shadow_frame, JValue result_register,
                                       bool interpret_one_instruction);
 
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index 267df2e..aa0f854 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -25,6 +25,7 @@
 
 namespace art {
 
+class CodeItemDataAccessor;
 class ShadowFrame;
 class Thread;
 
@@ -32,7 +33,7 @@
 
 template<bool do_access_check, bool transaction_active>
 JValue ExecuteSwitchImpl(Thread* self,
-                         const DexFile::CodeItem* code_item,
+                         const CodeItemDataAccessor& accessor,
                          ShadowFrame& shadow_frame,
                          JValue result_register,
                          bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc
index ab154cf..fe7e3e0 100644
--- a/runtime/interpreter/shadow_frame.cc
+++ b/runtime/interpreter/shadow_frame.cc
@@ -27,9 +27,9 @@
   } else if (m->IsNative()) {
     return GetVRegReference(0);
   } else {
-    const DexFile::CodeItem* code_item = m->GetCodeItem();
-    CHECK(code_item != nullptr) << ArtMethod::PrettyMethod(m);
-    uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+    CHECK(m->GetCodeItem() != nullptr) << ArtMethod::PrettyMethod(m);
+    CodeItemDataAccessor accessor(m);
+    uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
     return GetVRegReference(reg);
   }
 }
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index dece830..d1436fa 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1910,7 +1910,7 @@
   tables_initialized_ = true;
 }
 
-void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item,
+void UnstartedRuntime::Invoke(Thread* self, const CodeItemDataAccessor& accessor,
                               ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
@@ -1930,7 +1930,7 @@
     self->PopShadowFrame();
   } else {
     // Not special, continue with regular interpreter execution.
-    ArtInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
+    ArtInterpreterToInterpreterBridge(self, accessor, shadow_frame, result);
   }
 }
 
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index bc9ead8..2e86dea 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -25,6 +25,7 @@
 namespace art {
 
 class ArtMethod;
+class CodeItemDataAccessor;
 class Thread;
 class ShadowFrame;
 
@@ -48,7 +49,7 @@
   static void Initialize();
 
   static void Invoke(Thread* self,
-                     const DexFile::CodeItem* code_item,
+                     const CodeItemDataAccessor& accessor,
                      ShadowFrame* shadow_frame,
                      JValue* result,
                      size_t arg_offset)
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 278bc57..12bf79d 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -467,7 +467,8 @@
   // Fetch some data before looking up for an OSR method. We don't want thread
   // suspension once we hold an OSR method, as the JIT code cache could delete the OSR
   // method while we are being suspended.
-  const size_t number_of_vregs = method->GetCodeItem()->registers_size_;
+  CodeItemDataAccessor accessor(method);
+  const size_t number_of_vregs = accessor.RegistersSize();
   const char* shorty = method->GetShorty();
   std::string method_name(VLOG_IS_ON(jit) ? method->PrettyMethod() : "");
   void** memory = nullptr;
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 8eb31c1..88f30a8 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -408,7 +408,7 @@
                                             const InstructionOperands* const operands,
                                             JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
   // Compute method information.
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+  CodeItemDataAccessor accessor(called_method);
 
   // Number of registers for the callee's call frame. Note that for non-exact
   // invokes, we always derive this information from the callee method. We
@@ -419,10 +419,10 @@
   uint16_t num_regs;
   size_t num_input_regs;
   size_t first_dest_reg;
-  if (LIKELY(code_item != nullptr)) {
-    num_regs = code_item->registers_size_;
-    first_dest_reg = num_regs - code_item->ins_size_;
-    num_input_regs = code_item->ins_size_;
+  if (LIKELY(accessor.HasCodeItem())) {
+    num_regs = accessor.RegistersSize();
+    first_dest_reg = num_regs - accessor.InsSize();
+    num_input_regs = accessor.InsSize();
     // Parameter registers go at the end of the shadow frame.
     DCHECK_NE(first_dest_reg, (size_t)-1);
   } else {
@@ -496,7 +496,7 @@
   bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
       called_method, called_method->GetEntryPointFromQuickCompiledCode());
   PerformCall(self,
-              code_item,
+              accessor,
               shadow_frame.GetMethod(),
               first_dest_reg,
               new_shadow_frame,
@@ -550,10 +550,9 @@
   // - One for the only method argument (an EmulatedStackFrame).
   static constexpr size_t kNumRegsForTransform = 2;
 
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
-  DCHECK(code_item != nullptr);
-  DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_);
-  DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_);
+  CodeItemDataAccessor accessor(called_method);
+  DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize());
+  DCHECK_EQ(kNumRegsForTransform, accessor.InsSize());
 
   ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
       CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
@@ -589,7 +588,7 @@
   bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
       called_method, called_method->GetEntryPointFromQuickCompiledCode());
   PerformCall(self,
-              code_item,
+              accessor,
               shadow_frame.GetMethod(),
               0 /* first destination register */,
               new_shadow_frame,
@@ -1035,14 +1034,14 @@
   }
 
   // Compute method information.
-  const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+  CodeItemDataAccessor accessor(called_method);
   uint16_t num_regs;
   size_t num_input_regs;
   size_t first_dest_reg;
-  if (LIKELY(code_item != nullptr)) {
-    num_regs = code_item->registers_size_;
-    first_dest_reg = num_regs - code_item->ins_size_;
-    num_input_regs = code_item->ins_size_;
+  if (LIKELY(accessor.HasCodeItem())) {
+    num_regs = accessor.RegistersSize();
+    first_dest_reg = num_regs - accessor.InsSize();
+    num_input_regs = accessor.InsSize();
     // Parameter registers go at the end of the shadow frame.
     DCHECK_NE(first_dest_reg, (size_t)-1);
   } else {
@@ -1066,7 +1065,7 @@
   bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
       called_method, called_method->GetEntryPointFromQuickCompiledCode());
   PerformCall(self,
-              code_item,
+              accessor,
               shadow_frame.GetMethod(),
               first_dest_reg,
               new_shadow_frame,
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index cfef9c7..542692f 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1377,9 +1377,9 @@
   }
 
   // Is there any reason to believe there's any synchronization in this method?
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  CHECK(code_item != nullptr) << m->PrettyMethod();
-  if (code_item->tries_size_ == 0) {
+  CHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+  CodeItemDataAccessor accessor(m);
+  if (accessor.TriesSize() == 0) {
     return;  // No "tries" implies no synchronization, so no held locks to report.
   }
 
@@ -1399,11 +1399,10 @@
   for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) {
     // As a debug check, check that dex PC corresponds to a monitor-enter.
     if (kIsDebugBuild) {
-      const Instruction* monitor_enter_instruction =
-          Instruction::At(&code_item->insns_[dex_lock_info.dex_pc]);
-      CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER)
+      const Instruction& monitor_enter_instruction = accessor.InstructionAt(dex_lock_info.dex_pc);
+      CHECK_EQ(monitor_enter_instruction.Opcode(), Instruction::MONITOR_ENTER)
           << "expected monitor-enter @" << dex_lock_info.dex_pc << "; was "
-          << reinterpret_cast<const void*>(monitor_enter_instruction);
+          << reinterpret_cast<const void*>(&monitor_enter_instruction);
     }
 
     // Iterate through the set of dex registers, as the compiler may not have held all of them
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 32f8df7..f437db2 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1500,14 +1500,10 @@
   }
 }
 
-uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file,
-                                     const DexFile::CodeItem* code_item) {
-  if (code_item == nullptr) {
-    return 0;
-  }
-  const uint32_t debug_info_off = code_item->debug_info_off_;
+uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) {
   // Note that although the specification says that 0 should be used if there
   // is no debug information, some applications incorrectly use 0xFFFFFFFF.
+  // The following check also handles debug_info_off == 0.
   if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) {
     return debug_info_off;
   }
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 36a4d7b..1fb17a4 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -114,9 +114,9 @@
                                const char* abs_dex_location,
                                std::string* error_msg);
 
-  // Return the debug info offset of the code item `item` located in `dex_file`.
-  static uint32_t GetDebugInfoOffset(const DexFile& dex_file,
-                                     const DexFile::CodeItem* item);
+  // Return the actual debug info offset for an offset that might be actually pointing to
+  // dequickening info. The returned debug info offset is the one originally in the the dex file.
+  static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);
 
   virtual ~OatFile();
 
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index a7771ab..06b94c3 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -222,7 +222,8 @@
     self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
   }
 
-  const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_;
+  CodeItemDataAccessor accessor(handler_method_);
+  const size_t number_of_vregs = accessor.RegistersSize();
   CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo();
   CodeInfoEncoding encoding = code_info.ExtractEncoding();
 
@@ -359,7 +360,8 @@
       const size_t frame_id = GetFrameId();
       ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id);
       const bool* updated_vregs;
-      const size_t num_regs = method->GetCodeItem()->registers_size_;
+      CodeItemDataAccessor accessor(method);
+      const size_t num_regs = accessor.RegistersSize();
       if (new_frame == nullptr) {
         new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, method, GetDexPc());
         updated_vregs = nullptr;
@@ -406,7 +408,8 @@
     uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
     CodeInfoEncoding encoding = code_info.ExtractEncoding();
     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
-    const size_t number_of_vregs = m->GetCodeItem()->registers_size_;
+    CodeItemDataAccessor accessor(m);
+    const size_t number_of_vregs = accessor.RegistersSize();
     uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
     BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
     DexRegisterMap vreg_map = IsInInlinedFrame()
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5ad1f7c..bbea48b 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -154,13 +154,13 @@
       return cur_shadow_frame_->GetVRegReference(0);
     }
   } else {
-    const DexFile::CodeItem* code_item = m->GetCodeItem();
-    if (code_item == nullptr) {
+    CodeItemDataAccessor accessor(m);
+    if (!accessor.HasCodeItem()) {
       UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
           << ArtMethod::PrettyMethod(m);
       return nullptr;
     } else {
-      uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+      uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
       uint32_t value = 0;
       bool success = GetVReg(m, reg, kReferenceVReg, &value);
       // We currently always guarantee the `this` object is live throughout the method.
@@ -223,11 +223,11 @@
 bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
                                             uint32_t* val) const {
   DCHECK_EQ(m, GetMethod());
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  DCHECK(code_item != nullptr) << m->PrettyMethod();  // Can't be null or how would we compile
-                                                      // its instructions?
-  uint16_t number_of_dex_registers = code_item->registers_size_;
-  DCHECK_LT(vreg, code_item->registers_size_);
+  // Can't be null or how would we compile its instructions?
+  DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+  CodeItemDataAccessor accessor(m);
+  uint16_t number_of_dex_registers = accessor.RegistersSize();
+  DCHECK_LT(vreg, number_of_dex_registers);
   const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
   CodeInfo code_info = method_header->GetOptimizedCodeInfo();
   CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -395,8 +395,8 @@
                            uint16_t vreg,
                            uint32_t new_value,
                            VRegKind kind) {
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor accessor(m);
+  if (!accessor.HasCodeItem()) {
     return false;
   }
   ShadowFrame* shadow_frame = GetCurrentShadowFrame();
@@ -404,7 +404,7 @@
     // This is a compiled frame: we must prepare and update a shadow frame that will
     // be executed by the interpreter after deoptimization of the stack.
     const size_t frame_id = GetFrameId();
-    const uint16_t num_regs = code_item->registers_size_;
+    const uint16_t num_regs = accessor.RegistersSize();
     shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
     CHECK(shadow_frame != nullptr);
     // Remember the vreg has been set for debugging and must not be overwritten by the
@@ -432,15 +432,15 @@
     LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
     UNREACHABLE();
   }
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  if (code_item == nullptr) {
+  CodeItemDataAccessor accessor(m);
+  if (!accessor.HasCodeItem()) {
     return false;
   }
   ShadowFrame* shadow_frame = GetCurrentShadowFrame();
   if (shadow_frame == nullptr) {
     // This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger).
     const size_t frame_id = GetFrameId();
-    const uint16_t num_regs = code_item->registers_size_;
+    const uint16_t num_regs = accessor.RegistersSize();
     shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
     CHECK(shadow_frame != nullptr);
     // Remember the vreg pair has been set for debugging and must not be overwritten by the
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b86e56b..6babd75 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3425,7 +3425,7 @@
                        const CodeInfoEncoding& _encoding,
                        const StackMap& map,
                        RootVisitor& _visitor)
-          : number_of_dex_registers(method->GetCodeItem()->registers_size_),
+          : number_of_dex_registers(CodeItemDataAccessor(method).RegistersSize()),
             code_info(_code_info),
             encoding(_encoding),
             dex_register_map(code_info.GetDexRegisterMapOf(map,
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4ff49ed..be6915f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -350,13 +350,13 @@
   }
 }
 
-static bool IsLargeMethod(const DexFile::CodeItem* const code_item) {
-  if (code_item == nullptr) {
+static bool IsLargeMethod(const CodeItemDataAccessor& accessor) {
+  if (!accessor.HasCodeItem()) {
     return false;
   }
 
-  uint16_t registers_size = code_item->registers_size_;
-  uint32_t insns_size = code_item->insns_size_in_code_units_;
+  uint16_t registers_size = accessor.RegistersSize();
+  uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
 
   return registers_size * insns_size > 4*1024*1024;
 }
@@ -494,7 +494,7 @@
     if (duration_ns > MsToNs(100)) {
       LOG(WARNING) << "Verification of " << dex_file->PrettyMethod(method_idx)
                    << " took " << PrettyDuration(duration_ns)
-                   << (IsLargeMethod(code_item) ? " (large method)" : "");
+                   << (IsLargeMethod(verifier.CodeItem()) ? " (large method)" : "");
     }
   }
   result.types = verifier.encountered_failure_types_;
@@ -567,7 +567,7 @@
       dex_cache_(dex_cache),
       class_loader_(class_loader),
       class_def_(class_def),
-      code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
+      code_item_accessor_(dex_file, code_item),
       declaring_class_(nullptr),
       interesting_dex_pc_(-1),
       monitor_enter_dex_pcs_(nullptr),