Add CodeItemDebugInfoAccessor

Use it in places where DecodeDebugPositionInfo is called.

Motivation: Abstract away calls to GetDebugInfoOffset.

Bug: 63756964
Test: test-art-host
Test: art/tools/run-jdwp-tests.sh '--mode=host' --debug

Change-Id: I3ab2eff56c472cc717f49d17fd17eb0b8fde4062
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index d599994..81a0a69 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "art_field-inl.h"
+#include "code_item_accessors-inl.h"
 #include "debug/dwarf/debug_abbrev_writer.h"
 #include "debug/dwarf/debug_info_entry_writer.h"
 #include "debug/elf_compilation_unit.h"
@@ -48,10 +49,10 @@
 
 static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
   std::vector<const char*> names;
-  if (mi->code_item != nullptr) {
+  CodeItemDebugInfoAccessor accessor(mi->dex_file, mi->code_item);
+  if (accessor.HasCodeItem()) {
     DCHECK(mi->dex_file != nullptr);
-    uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*mi->dex_file, mi->code_item);
-    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(debug_info_offset);
+    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(accessor.DebugInfoOffset());
     if (stream != nullptr) {
       DecodeUnsignedLeb128(&stream);  // line.
       uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
@@ -162,7 +163,7 @@
     for (auto mi : compilation_unit.methods) {
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      const DexFile::CodeItem* dex_code = mi->code_item;
+      CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
       const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
       const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
       const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
@@ -204,13 +205,13 @@
       // Decode dex register locations for all stack maps.
       // It might be expensive, so do it just once and reuse the result.
       std::vector<DexRegisterMap> dex_reg_maps;
-      if (dex_code != nullptr && mi->code_info != nullptr) {
+      if (accessor.HasCodeItem() && mi->code_info != nullptr) {
         const CodeInfo code_info(mi->code_info);
         CodeInfoEncoding encoding = code_info.ExtractEncoding();
         for (size_t s = 0; s < code_info.GetNumberOfStackMaps(encoding); ++s) {
           const StackMap& stack_map = code_info.GetStackMapAt(s, encoding);
           dex_reg_maps.push_back(code_info.GetDexRegisterMapOf(
-              stack_map, encoding, dex_code->registers_size_));
+              stack_map, encoding, accessor.RegistersSize()));
         }
       }
 
@@ -224,9 +225,9 @@
         WriteName("this");
         info_.WriteFlagPresent(DW_AT_artificial);
         WriteLazyType(dex_class_desc);
-        if (dex_code != nullptr) {
+        if (accessor.HasCodeItem()) {
           // Write the stack location of the parameter.
-          const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+          const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
           const bool is64bitValue = false;
           WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
         }
@@ -244,30 +245,31 @@
           const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
           WriteLazyType(type_desc);
           const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
-          if (dex_code != nullptr) {
+          if (accessor.HasCodeItem()) {
             // Write the stack location of the parameter.
-            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+            const uint32_t vreg = accessor.RegistersSize() - accessor.InsSize() + arg_reg;
             WriteRegLocation(mi, dex_reg_maps, vreg, is64bitValue, compilation_unit.code_address);
           }
           arg_reg += is64bitValue ? 2 : 1;
           info_.EndTag();
         }
-        if (dex_code != nullptr) {
-          DCHECK_EQ(arg_reg, dex_code->ins_size_);
+        if (accessor.HasCodeItem()) {
+          DCHECK_EQ(arg_reg, accessor.InsSize());
         }
       }
 
       // Write local variables.
       LocalInfos local_infos;
-      uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, dex_code);
-      if (dex->DecodeDebugLocalInfo(dex_code,
-                                    debug_info_offset,
+      if (dex->DecodeDebugLocalInfo(accessor.RegistersSize(),
+                                    accessor.InsSize(),
+                                    accessor.InsnsSizeInCodeUnits(),
+                                    accessor.DebugInfoOffset(),
                                     is_static,
                                     mi->dex_method_index,
                                     LocalInfoCallback,
                                     &local_infos)) {
         for (const DexFile::LocalInfo& var : local_infos) {
-          if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+          if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) {
             info_.StartTag(DW_TAG_variable);
             WriteName(var.name_);
             WriteLazyType(var.descriptor_);
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index 943e03a..c7224fc 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -159,9 +159,9 @@
       PositionInfos dex2line_map;
       DCHECK(mi->dex_file != nullptr);
       const DexFile* dex = mi->dex_file;
-      uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex, mi->code_item);
-      if (!dex->DecodeDebugPositionInfo(
-              mi->code_item, debug_info_offset, PositionInfoCallback, &dex2line_map)) {
+      CodeItemDebugInfoAccessor accessor(dex, mi->code_item);
+      const uint32_t debug_info_offset = accessor.DebugInfoOffset();
+      if (!dex->DecodeDebugPositionInfo(debug_info_offset, PositionInfoCallback, &dex2line_map)) {
         continue;
       }
 
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 782546c..fc7b28c 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -442,17 +442,15 @@
       return false;
     }
   };
-  const uint32_t num_instructions = code_item_->insns_size_in_code_units_;
+  CodeItemDebugInfoAccessor accessor(dex_file_, code_item_);
   ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_,
-                                                     num_instructions,
+                                                     accessor.InsnsSizeInCodeUnits(),
                                                      /* expandable */ false,
                                                      kArenaAllocGraphBuilder);
   locations->ClearAllBits();
-  uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file_, code_item_);
-  dex_file_->DecodeDebugPositionInfo(code_item_, debug_info_offset, Callback::Position, locations);
+  dex_file_->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), Callback::Position, locations);
   // Instruction-specific tweaks.
-  IterationRange<DexInstructionIterator> instructions = code_item_->Instructions();
-  for (const DexInstructionPcPair& inst : instructions) {
+  for (const DexInstructionPcPair& inst : accessor) {
     switch (inst->Opcode()) {
       case Instruction::MOVE_EXCEPTION: {
         // Stop in native debugger after the exception has been moved.
@@ -461,7 +459,7 @@
         locations->ClearBit(inst.DexPc());
         DexInstructionIterator next = std::next(DexInstructionIterator(inst));
         DCHECK(next.DexPc() != inst.DexPc());
-        if (next != instructions.end()) {
+        if (next != accessor.end()) {
           locations->SetBit(next.DexPc());
         }
         break;
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index b5c5d98..260888e 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -2694,7 +2694,8 @@
           CompiledMethod* compiled_method =
               driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
           const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
-          uint32_t existing_debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
+          CodeItemDebugInfoAccessor accessor(dex_file, code_item);
+          const uint32_t existing_debug_info_offset = accessor.DebugInfoOffset();
           // If the existing offset is already out of bounds (and not magic marker 0xFFFFFFFF)
           // we will pretend the method has been quickened.
           bool existing_offset_out_of_bounds =
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index a7af193..527a5b9 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1203,10 +1203,16 @@
   bool is_static = (flags & kAccStatic) != 0;
   fprintf(gOutFile, "      positions     : \n");
   uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
-  pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, dumpPositionsCb, nullptr);
+  pDexFile->DecodeDebugPositionInfo(debug_info_offset, dumpPositionsCb, nullptr);
   fprintf(gOutFile, "      locals        : \n");
-  pDexFile->DecodeDebugLocalInfo(
-      pCode, debug_info_offset, is_static, idx, dumpLocalsCb, nullptr);
+  pDexFile->DecodeDebugLocalInfo(pCode->registers_size_,
+                                 pCode->ins_size_,
+                                 pCode->insns_size_in_code_units_,
+                                 debug_info_offset,
+                                 is_static,
+                                 idx,
+                                 dumpLocalsCb,
+                                 nullptr);
 }
 
 /*
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 3bd903d..4bf0475 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -121,7 +121,7 @@
   // Find the first line.
   int firstLine = -1;
   uint32_t debug_info_offset = pDexFile->GetDebugInfoOffset(pCode);
-  pDexFile->DecodeDebugPositionInfo(pCode, debug_info_offset, positionsCb, &firstLine);
+  pDexFile->DecodeDebugPositionInfo(debug_info_offset, positionsCb, &firstLine);
 
   // Method signature.
   const Signature signature = pDexFile->GetMethodSignature(pMethodId);
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 448ce41..4444853 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -37,6 +37,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "base/mutex-inl.h"
+#include "code_item_accessors-inl.h"
 #include "dex_file_annotations.h"
 #include "dex_file_types.h"
 #include "events-inl.h"
@@ -190,12 +191,17 @@
   }
 
   art::ScopedObjectAccess soa(art::Thread::Current());
-  const art::DexFile* dex_file = art_method->GetDexFile();
-  const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
-  // TODO code_item == nullptr means that the method is abstract (or native, but we check that
+
+  const art::DexFile* const dex_file = art_method->GetDexFile();
+  if (dex_file == nullptr) {
+    return ERR(ABSENT_INFORMATION);
+  }
+
+  // TODO HasCodeItem == false means that the method is abstract (or native, but we check that
   // earlier). We should check what is returned by the RI in this situation since it's not clear
   // what the appropriate return value is from the spec.
-  if (dex_file == nullptr || code_item == nullptr) {
+  art::CodeItemDebugInfoAccessor accessor(art_method);
+  if (!accessor.HasCodeItem()) {
     return ERR(ABSENT_INFORMATION);
   }
 
@@ -260,9 +266,10 @@
   };
 
   LocalVariableContext context(env);
-  uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
-  if (!dex_file->DecodeDebugLocalInfo(code_item,
-                                      debug_info_offset,
+  if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
+                                      accessor.InsSize(),
+                                      accessor.InsnsSizeInCodeUnits(),
+                                      accessor.DebugInfoOffset(),
                                       art_method->IsStatic(),
                                       art_method->GetDexMethodIndex(),
                                       LocalVariableContext::Callback,
@@ -462,7 +469,7 @@
   art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
   DCHECK(!art_method->IsRuntimeMethod());
 
-  const art::DexFile::CodeItem* code_item;
+  art::CodeItemDebugInfoAccessor accessor;
   const art::DexFile* dex_file;
   {
     art::ScopedObjectAccess soa(art::Thread::Current());
@@ -477,15 +484,14 @@
       return ERR(NULL_POINTER);
     }
 
-    code_item = art_method->GetCodeItem();
+    accessor = art::CodeItemDebugInfoAccessor(art_method);
     dex_file = art_method->GetDexFile();
-    DCHECK(code_item != nullptr) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
+    DCHECK(accessor.HasCodeItem()) << art_method->PrettyMethod() << " " << dex_file->GetLocation();
   }
 
   LineNumberContext context;
-  uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
   bool success = dex_file->DecodeDebugPositionInfo(
-      code_item, debug_info_offset, CollectLineNumbers, &context);
+      accessor.DebugInfoOffset(), CollectLineNumbers, &context);
   if (!success) {
     return ERR(ABSENT_INFORMATION);
   }
@@ -613,8 +619,11 @@
                          /*out*/art::Primitive::Type* type)
       REQUIRES(art::Locks::mutator_lock_) {
     const art::DexFile* dex_file = method->GetDexFile();
-    const art::DexFile::CodeItem* code_item = method->GetCodeItem();
-    if (dex_file == nullptr || code_item == nullptr) {
+    if (dex_file == nullptr) {
+      return ERR(OPAQUE_FRAME);
+    }
+    art::CodeItemDebugInfoAccessor accessor(method);
+    if (!accessor.HasCodeItem()) {
       return ERR(OPAQUE_FRAME);
     }
 
@@ -653,9 +662,10 @@
     };
 
     GetLocalVariableInfoContext context(slot_, dex_pc, descriptor, type);
-    uint32_t debug_info_offset = art::OatFile::GetDebugInfoOffset(*dex_file, code_item);
-    if (!dex_file->DecodeDebugLocalInfo(code_item,
-                                        debug_info_offset,
+    if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(),
+                                        accessor.InsSize(),
+                                        accessor.InsnsSizeInCodeUnits(),
+                                        accessor.DebugInfoOffset(),
                                         method->IsStatic(),
                                         method->GetDexMethodIndex(),
                                         GetLocalVariableInfoContext::Callback,
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
index d04849d..4f4d8cc 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/code_item_accessors-inl.h
@@ -22,6 +22,7 @@
 #include "art_method-inl.h"
 #include "cdex/compact_dex_file.h"
 #include "dex_file-inl.h"
+#include "oat_file.h"
 #include "standard_dex_file.h"
 
 namespace art {
@@ -37,7 +38,7 @@
 }
 
 inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
-                                               const DexFile::CodeItem* code_item) {
+                                              const DexFile::CodeItem* code_item) {
   DCHECK(dex_file != nullptr);
   DCHECK(code_item != nullptr);
   if (dex_file->IsCompactDexFile()) {
@@ -150,6 +151,31 @@
   return index != -1 ? &try_items.begin()[index] : nullptr;
 }
 
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
+    : CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {}
+
+inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile* dex_file,
+                                                            const DexFile::CodeItem* code_item) {
+  if (code_item == nullptr) {
+    return;
+  }
+  debug_info_offset_ = OatFile::GetDebugInfoOffset(*dex_file, code_item);
+  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));
+  }
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item) {
+  CodeItemDataAccessor::Init(code_item);
+}
+
+inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
+  CodeItemDataAccessor::Init(code_item);
+}
+
 }  // 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 aa1305a..a089a27 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/code_item_accessors.h
@@ -132,6 +132,30 @@
   uint16_t tries_size_;
 };
 
+// Abstract accesses to code item data including debug info offset. More heavy weight than the other
+// helpers.
+class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
+ public:
+  CodeItemDebugInfoAccessor() = default;
+
+  // Handles null code items, but not null dex files.
+  ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile* dex_file,
+                                          const DexFile::CodeItem* code_item);
+
+  ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
+
+  uint32_t DebugInfoOffset() const {
+    return debug_info_offset_;
+  }
+
+ protected:
+  ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
+  ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
+
+ private:
+  uint32_t debug_info_offset_ = 0u;
+};
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 13029fb..541bd1d 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1661,16 +1661,16 @@
     }
   };
   ArtMethod* m = FromMethodId(method_id);
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
+  CodeItemDebugInfoAccessor accessor(m);
   uint64_t start, end;
-  if (code_item == nullptr) {
+  if (!accessor.HasCodeItem()) {
     DCHECK(m->IsNative() || m->IsProxyMethod());
     start = -1;
     end = -1;
   } else {
     start = 0;
     // Return the index of the last instruction
-    end = code_item->insns_size_in_code_units_ - 1;
+    end = accessor.InsnsSizeInCodeUnits() - 1;
   }
 
   expandBufAdd8BE(pReply, start);
@@ -1684,10 +1684,10 @@
   context.numItems = 0;
   context.pReply = pReply;
 
-  if (code_item != nullptr) {
-    uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
-    m->GetDexFile()->DecodeDebugPositionInfo(
-        code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+  if (accessor.HasCodeItem()) {
+    m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+                                             DebugCallbackContext::Callback,
+                                             &context);
   }
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + numLinesOffset, context.numItems);
@@ -1727,6 +1727,7 @@
     }
   };
   ArtMethod* m = FromMethodId(method_id);
+  CodeItemDebugInfoAccessor accessor(m);
 
   // arg_count considers doubles and longs to take 2 units.
   // variable_count considers everything to take 1 unit.
@@ -1742,12 +1743,15 @@
   context.variable_count = 0;
   context.with_generic = with_generic;
 
-  const DexFile::CodeItem* code_item = m->GetCodeItem();
-  if (code_item != nullptr) {
-    uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
-    m->GetDexFile()->DecodeDebugLocalInfo(
-        code_item, debug_info_offset, m->IsStatic(), m->GetDexMethodIndex(),
-        DebugCallbackContext::Callback, &context);
+  if (accessor.HasCodeItem()) {
+    m->GetDexFile()->DecodeDebugLocalInfo(accessor.RegistersSize(),
+                                          accessor.InsSize(),
+                                          accessor.InsnsSizeInCodeUnits(),
+                                          accessor.DebugInfoOffset(),
+                                          m->IsStatic(),
+                                          m->GetDexMethodIndex(),
+                                          DebugCallbackContext::Callback,
+                                          &context);
   }
 
   JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
@@ -3836,9 +3840,9 @@
   // Find the dex_pc values that correspond to the current line, for line-based single-stepping.
   struct DebugCallbackContext {
     DebugCallbackContext(SingleStepControl* single_step_control_cb,
-                         int32_t line_number_cb, const DexFile::CodeItem* code_item)
+                         int32_t line_number_cb, uint32_t num_insns_in_code_units)
         : single_step_control_(single_step_control_cb), line_number_(line_number_cb),
-          code_item_(code_item), last_pc_valid(false), last_pc(0) {
+          num_insns_in_code_units_(num_insns_in_code_units), last_pc_valid(false), last_pc(0) {
     }
 
     static bool Callback(void* raw_context, const DexFile::PositionInfo& entry) {
@@ -3864,8 +3868,7 @@
     ~DebugCallbackContext() {
       // If the line number was the last in the position table...
       if (last_pc_valid) {
-        size_t end = code_item_->insns_size_in_code_units_;
-        for (uint32_t dex_pc = last_pc; dex_pc < end; ++dex_pc) {
+        for (uint32_t dex_pc = last_pc; dex_pc < num_insns_in_code_units_; ++dex_pc) {
           single_step_control_->AddDexPc(dex_pc);
         }
       }
@@ -3873,7 +3876,7 @@
 
     SingleStepControl* const single_step_control_;
     const int32_t line_number_;
-    const DexFile::CodeItem* const code_item_;
+    const uint32_t num_insns_in_code_units_;
     bool last_pc_valid;
     uint32_t last_pc;
   };
@@ -3892,11 +3895,11 @@
   // Note: if the thread is not running Java code (pure native thread), there is no "current"
   // method on the stack (and no line number either).
   if (m != nullptr && !m->IsNative()) {
-    const DexFile::CodeItem* const code_item = m->GetCodeItem();
-    DebugCallbackContext context(single_step_control, line_number, code_item);
-    uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*(m->GetDexFile()), code_item);
-    m->GetDexFile()->DecodeDebugPositionInfo(
-        code_item, debug_info_offset, DebugCallbackContext::Callback, &context);
+    CodeItemDebugInfoAccessor accessor(m);
+    DebugCallbackContext context(single_step_control, line_number, accessor.InsnsSizeInCodeUnits());
+    m->GetDexFile()->DecodeDebugPositionInfo(accessor.DebugInfoOffset(),
+                                             DebugCallbackContext::Callback,
+                                             &context);
   }
 
   // Activate single-step in the thread.
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 1880968..1c76a32 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -385,13 +385,16 @@
 }
 
 template<typename NewLocalCallback>
-bool DexFile::DecodeDebugLocalInfo(const CodeItem* code_item,
+bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
+                                   uint32_t ins_size,
+                                   uint32_t insns_size_in_code_units,
                                    uint32_t debug_info_offset,
                                    bool is_static,
                                    uint32_t method_idx,
                                    NewLocalCallback new_local_callback,
                                    void* context) const {
-  if (code_item == nullptr) {
+  const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
+  if (stream == nullptr) {
     return false;
   }
   std::vector<const char*> arg_descriptors;
@@ -399,15 +402,15 @@
   for (; it.HasNext(); it.Next()) {
     arg_descriptors.push_back(it.GetDescriptor());
   }
-  return DecodeDebugLocalInfo(GetDebugInfoStream(debug_info_offset),
+  return DecodeDebugLocalInfo(stream,
                               GetLocation(),
                               GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
                               arg_descriptors,
                               this->PrettyMethod(method_idx),
                               is_static,
-                              code_item->registers_size_,
-                              code_item->ins_size_,
-                              code_item->insns_size_in_code_units_,
+                              registers_size,
+                              ins_size,
+                              insns_size_in_code_units,
                               [this](uint32_t idx) {
                                 return StringDataByIdx(dex::StringIndex(idx));
                               },
@@ -488,13 +491,9 @@
 }
 
 template<typename DexDebugNewPosition>
-bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item,
-                                      uint32_t debug_info_offset,
+bool DexFile::DecodeDebugPositionInfo(uint32_t debug_info_offset,
                                       DexDebugNewPosition position_functor,
                                       void* context) const {
-  if (code_item == nullptr) {
-    return false;
-  }
   return DecodeDebugPositionInfo(GetDebugInfoStream(debug_info_offset),
                                  [this](uint32_t idx) {
                                    return StringDataByIdx(dex::StringIndex(idx));
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 944a308..91ec630 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -954,7 +954,9 @@
                                    NewLocalCallback new_local,
                                    void* context);
   template<typename NewLocalCallback>
-  bool DecodeDebugLocalInfo(const CodeItem* code_item,
+  bool DecodeDebugLocalInfo(uint32_t registers_size,
+                            uint32_t ins_size,
+                            uint32_t insns_size_in_code_units,
                             uint32_t debug_info_offset,
                             bool is_static,
                             uint32_t method_idx,
@@ -968,8 +970,7 @@
                                       DexDebugNewPosition position_functor,
                                       void* context);
   template<typename DexDebugNewPosition>
-  bool DecodeDebugPositionInfo(const CodeItem* code_item,
-                               uint32_t debug_info_offset,
+  bool DecodeDebugPositionInfo(uint32_t debug_info_offset,
                                DexDebugNewPosition position_functor,
                                void* context) const;
 
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index b44bd51..837291b 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -1567,14 +1567,12 @@
     return -2;
   }
 
-  const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
-  DCHECK(code_item != nullptr) << method->PrettyMethod() << " " << dex_file->GetLocation();
+  CodeItemDebugInfoAccessor accessor(method);
+  DCHECK(accessor.HasCodeItem()) << method->PrettyMethod() << " " << dex_file->GetLocation();
 
   // A method with no line number info should return -1
   DexFile::LineNumFromPcContext context(rel_pc, -1);
-  uint32_t debug_info_offset = OatFile::GetDebugInfoOffset(*dex_file, code_item);
-  dex_file->DecodeDebugPositionInfo(
-      code_item, debug_info_offset, DexFile::LineNumForPcCb, &context);
+  dex_file->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), DexFile::LineNumForPcCb, &context);
   return context.line_num_;
 }
 
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 14c36b4..6905504 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -731,7 +731,14 @@
   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, debug_info_offset, true, 1, Callback, nullptr));
+  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));
 }
 
 }  // namespace art