Use iterators to access stack map data.

Try to simplify the code using the recently added iterators.

Test: test-art-host-gtest-stack_map_test
Change-Id: I0b9f54df01749ee6ec3a67cfb07ba636a2489c89
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index f2a942f..bda7108 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -208,8 +208,7 @@
       std::vector<DexRegisterMap> dex_reg_maps;
       if (accessor.HasCodeItem() && mi->code_info != nullptr) {
         code_info.reset(new CodeInfo(mi->code_info));
-        for (size_t s = 0; s < code_info->GetNumberOfStackMaps(); ++s) {
-          const StackMap stack_map = code_info->GetStackMapAt(s);
+        for (StackMap stack_map : code_info->GetStackMaps()) {
           dex_reg_maps.push_back(code_info->GetDexRegisterMapOf(stack_map));
         }
       }
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
index a7adab5..3d78943 100644
--- a/compiler/debug/elf_debug_line_writer.h
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -101,9 +101,7 @@
         // Use stack maps to create mapping table from pc to dex.
         const CodeInfo code_info(mi->code_info);
         pc2dex_map.reserve(code_info.GetNumberOfStackMaps());
-        for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
-          StackMap stack_map = code_info.GetStackMapAt(s);
-          DCHECK(stack_map.IsValid());
+        for (StackMap stack_map : code_info.GetStackMaps()) {
           const uint32_t pc = stack_map.GetNativePcOffset(isa);
           const int32_t dex = stack_map.GetDexPc();
           pc2dex_map.push_back({pc, dex});
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index 5d361953..3e1a36d 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -151,7 +151,7 @@
       StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
       CHECK_EQ(stack_map.HasDexRegisterMap(), (num_dex_registers != 0));
       CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0));
-      CHECK_EQ(code_info.GetInlineDepthOf(stack_map), inlining_depth);
+      CHECK_EQ(code_info.GetInlineInfosOf(stack_map).size(), inlining_depth);
     });
   }
 }
@@ -209,7 +209,7 @@
     size_t depth = current_inline_infos_.size() - 1;
     dchecks_.emplace_back([=](const CodeInfo& code_info) {
       StackMap stack_map = code_info.GetStackMapAt(stack_map_index);
-      InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth);
+      InlineInfo inline_info = code_info.GetInlineInfosOf(stack_map)[depth];
       CHECK_EQ(inline_info.GetDexPc(), dex_pc);
       bool encode_art_method = EncodeArtMethodInInlineInfo(method);
       CHECK_EQ(inline_info.EncodesArtMethod(), encode_art_method);
@@ -275,7 +275,6 @@
 
   if (kVerifyStackMaps) {
     size_t stack_map_index = stack_maps_.size();
-    uint32_t depth = current_inline_infos_.size();
     // We need to make copy of the current registers for later (when the check is run).
     auto expected_dex_registers = std::make_shared<dchecked_vector<DexRegisterLocation>>(
         current_dex_registers_.begin(), current_dex_registers_.end());
@@ -285,8 +284,9 @@
       for (DexRegisterLocation reg : code_info.GetDexRegisterMapOf(stack_map)) {
         CHECK_EQ((*expected_dex_registers)[expected_reg++], reg);
       }
-      for (uint32_t d = 0; d < depth; d++) {
-        for (DexRegisterLocation reg : code_info.GetDexRegisterMapAtDepth(d, stack_map)) {
+      for (InlineInfo inline_info : code_info.GetInlineInfosOf(stack_map)) {
+        DexRegisterMap map = code_info.GetInlineDexRegisterMapOf(stack_map, inline_info);
+        for (DexRegisterLocation reg : map) {
           CHECK_EQ((*expected_dex_registers)[expected_reg++], reg);
         }
       }
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 6241e0c..9ed90a4 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -193,13 +193,12 @@
     ASSERT_EQ(-2, location1.GetValue());
 
     ASSERT_TRUE(stack_map.HasInlineInfo());
-    InlineInfo inline_info0 = code_info.GetInlineInfoAtDepth(stack_map, 0);
-    InlineInfo inline_info1 = code_info.GetInlineInfoAtDepth(stack_map, 1);
-    ASSERT_EQ(2u, code_info.GetInlineDepthOf(stack_map));
-    ASSERT_EQ(3u, inline_info0.GetDexPc());
-    ASSERT_EQ(2u, inline_info1.GetDexPc());
-    ASSERT_TRUE(inline_info0.EncodesArtMethod());
-    ASSERT_TRUE(inline_info1.EncodesArtMethod());
+    auto inline_infos = code_info.GetInlineInfosOf(stack_map);
+    ASSERT_EQ(2u, inline_infos.size());
+    ASSERT_EQ(3u, inline_infos[0].GetDexPc());
+    ASSERT_EQ(2u, inline_infos[1].GetDexPc());
+    ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
+    ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
   }
 
   // Second stack map.
@@ -614,19 +613,18 @@
     ASSERT_EQ(0, dex_registers0[0].GetStackOffsetInBytes());
     ASSERT_EQ(4, dex_registers0[1].GetConstant());
 
-    InlineInfo if0_0 = ci.GetInlineInfoAtDepth(sm0, 0);
-    InlineInfo if0_1 = ci.GetInlineInfoAtDepth(sm0, 1);
-    ASSERT_EQ(2u, ci.GetInlineDepthOf(sm0));
-    ASSERT_EQ(2u, if0_0.GetDexPc());
-    ASSERT_TRUE(if0_0.EncodesArtMethod());
-    ASSERT_EQ(3u, if0_1.GetDexPc());
-    ASSERT_TRUE(if0_1.EncodesArtMethod());
+    auto inline_infos = ci.GetInlineInfosOf(sm0);
+    ASSERT_EQ(2u, inline_infos.size());
+    ASSERT_EQ(2u, inline_infos[0].GetDexPc());
+    ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
+    ASSERT_EQ(3u, inline_infos[1].GetDexPc());
+    ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
 
-    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm0);
+    DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[0]);
     ASSERT_EQ(1u, dex_registers1.size());
     ASSERT_EQ(8, dex_registers1[0].GetStackOffsetInBytes());
 
-    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm0);
+    DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm0, inline_infos[1]);
     ASSERT_EQ(3u, dex_registers2.size());
     ASSERT_EQ(16, dex_registers2[0].GetStackOffsetInBytes());
     ASSERT_EQ(20, dex_registers2[1].GetConstant());
@@ -642,22 +640,20 @@
     ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
     ASSERT_EQ(0, dex_registers0[1].GetConstant());
 
-    InlineInfo if1_0 = ci.GetInlineInfoAtDepth(sm1, 0);
-    InlineInfo if1_1 = ci.GetInlineInfoAtDepth(sm1, 1);
-    InlineInfo if1_2 = ci.GetInlineInfoAtDepth(sm1, 2);
-    ASSERT_EQ(3u, ci.GetInlineDepthOf(sm1));
-    ASSERT_EQ(2u, if1_0.GetDexPc());
-    ASSERT_TRUE(if1_0.EncodesArtMethod());
-    ASSERT_EQ(3u, if1_1.GetDexPc());
-    ASSERT_TRUE(if1_1.EncodesArtMethod());
-    ASSERT_EQ(5u, if1_2.GetDexPc());
-    ASSERT_TRUE(if1_2.EncodesArtMethod());
+    auto inline_infos = ci.GetInlineInfosOf(sm1);
+    ASSERT_EQ(3u, inline_infos.size());
+    ASSERT_EQ(2u, inline_infos[0].GetDexPc());
+    ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
+    ASSERT_EQ(3u, inline_infos[1].GetDexPc());
+    ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
+    ASSERT_EQ(5u, inline_infos[2].GetDexPc());
+    ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
 
-    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm1);
+    DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[0]);
     ASSERT_EQ(1u, dex_registers1.size());
     ASSERT_EQ(12, dex_registers1[0].GetStackOffsetInBytes());
 
-    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm1);
+    DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm1, inline_infos[1]);
     ASSERT_EQ(3u, dex_registers2.size());
     ASSERT_EQ(80, dex_registers2[0].GetStackOffsetInBytes());
     ASSERT_EQ(10, dex_registers2[1].GetConstant());
@@ -684,22 +680,20 @@
     ASSERT_EQ(56, dex_registers0[0].GetStackOffsetInBytes());
     ASSERT_EQ(0, dex_registers0[1].GetConstant());
 
-    InlineInfo if2_0 = ci.GetInlineInfoAtDepth(sm3, 0);
-    InlineInfo if2_1 = ci.GetInlineInfoAtDepth(sm3, 1);
-    InlineInfo if2_2 = ci.GetInlineInfoAtDepth(sm3, 2);
-    ASSERT_EQ(3u, ci.GetInlineDepthOf(sm3));
-    ASSERT_EQ(2u, if2_0.GetDexPc());
-    ASSERT_TRUE(if2_0.EncodesArtMethod());
-    ASSERT_EQ(5u, if2_1.GetDexPc());
-    ASSERT_TRUE(if2_1.EncodesArtMethod());
-    ASSERT_EQ(10u, if2_2.GetDexPc());
-    ASSERT_TRUE(if2_2.EncodesArtMethod());
+    auto inline_infos = ci.GetInlineInfosOf(sm3);
+    ASSERT_EQ(3u, inline_infos.size());
+    ASSERT_EQ(2u, inline_infos[0].GetDexPc());
+    ASSERT_TRUE(inline_infos[0].EncodesArtMethod());
+    ASSERT_EQ(5u, inline_infos[1].GetDexPc());
+    ASSERT_TRUE(inline_infos[1].EncodesArtMethod());
+    ASSERT_EQ(10u, inline_infos[2].GetDexPc());
+    ASSERT_TRUE(inline_infos[2].EncodesArtMethod());
 
-    DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, sm3);
+    DexRegisterMap dex_registers1 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[1]);
     ASSERT_EQ(1u, dex_registers1.size());
     ASSERT_EQ(2, dex_registers1[0].GetMachineRegister());
 
-    DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, sm3);
+    DexRegisterMap dex_registers2 = ci.GetInlineDexRegisterMapOf(sm3, inline_infos[2]);
     ASSERT_EQ(2u, dex_registers2.size());
     ASSERT_FALSE(dex_registers2[0].IsLive());
     ASSERT_EQ(3, dex_registers2[1].GetMachineRegister());
diff --git a/libartbase/base/bit_table.h b/libartbase/base/bit_table.h
index b0fc4d1..218203f 100644
--- a/libartbase/base/bit_table.h
+++ b/libartbase/base/bit_table.h
@@ -26,6 +26,7 @@
 
 #include "base/bit_memory_region.h"
 #include "base/casts.h"
+#include "base/iteration_range.h"
 #include "base/memory_region.h"
 #include "base/scoped_arena_containers.h"
 #include "base/stl_util.h"
@@ -207,9 +208,18 @@
     bool operator>=(const_iterator i) const { DCHECK(table_ == i.table_); return row_ >= i.row_; }
     bool operator<(const_iterator i) const { DCHECK(table_ == i.table_); return row_ < i.row_; }
     bool operator>(const_iterator i) const { DCHECK(table_ == i.table_); return row_ > i.row_; }
-    Accessor operator*() { return Accessor(table_, row_); }
-    Accessor operator->() { return Accessor(table_, row_); }
-    Accessor operator[](size_t index) { return Accessor(table_, row_ + index); }
+    Accessor operator*() {
+      DCHECK_LT(row_, table_->NumRows());
+      return Accessor(table_, row_);
+    }
+    Accessor operator->() {
+      DCHECK_LT(row_, table_->NumRows());
+      return Accessor(table_, row_);
+    }
+    Accessor operator[](size_t index) {
+      DCHECK_LT(row_ + index, table_->NumRows());
+      return Accessor(table_, row_ + index);
+    }
    private:
     const BitTable* table_ = nullptr;
     uint32_t row_ = 0;
@@ -236,6 +246,34 @@
   return a + n;
 }
 
+template<typename Accessor>
+class BitTableRange : public IterationRange<typename BitTable<Accessor>::const_iterator> {
+ public:
+  typedef typename BitTable<Accessor>::const_iterator const_iterator;
+
+  using IterationRange<const_iterator>::IterationRange;
+  BitTableRange() : IterationRange<const_iterator>(const_iterator(), const_iterator()) { }
+
+  bool empty() const { return this->begin() == this->end(); }
+  size_t size() const { return this->end() - this->begin(); }
+
+  Accessor operator[](size_t index) const {
+    const_iterator it = this->begin() + index;
+    DCHECK(it < this->end());
+    return *it;
+  }
+
+  Accessor back() const {
+    DCHECK(!empty());
+    return *(this->end() - 1);
+  }
+
+  void pop_back() {
+    DCHECK(!empty());
+    --this->last_;
+  }
+};
+
 // Helper class for encoding BitTable. It can optionally de-duplicate the inputs.
 template<uint32_t kNumColumns>
 class BitTableBuilderBase {
diff --git a/libartbase/base/iteration_range.h b/libartbase/base/iteration_range.h
index 76049a7..cd87d85 100644
--- a/libartbase/base/iteration_range.h
+++ b/libartbase/base/iteration_range.h
@@ -39,9 +39,9 @@
   iterator cbegin() const { return first_; }
   iterator cend() const { return last_; }
 
- private:
-  const iterator first_;
-  const iterator last_;
+ protected:
+  iterator first_;
+  iterator last_;
 };
 
 template <typename Iter>
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 4a3d3b0..40ef10f 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -46,38 +46,38 @@
 
 inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
                                     const MethodInfo& method_info,
-                                    const CodeInfo& code_info,
-                                    const StackMap& stack_map,
-                                    uint8_t inlining_depth)
+                                    const BitTableRange<InlineInfo>& inline_infos)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(!outer_method->IsObsolete());
-  InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, inlining_depth);
 
   // This method is being used by artQuickResolutionTrampoline, before it sets up
   // the passed parameters in a GC friendly way. Therefore we must never be
   // suspended while executing it.
   ScopedAssertNoThreadSuspension sants(__FUNCTION__);
 
-  if (inline_info.EncodesArtMethod()) {
-    return inline_info.GetArtMethod();
-  }
+  {
+    InlineInfo inline_info = inline_infos.back();
 
-  uint32_t method_index = inline_info.GetMethodIndex(method_info);
-  if (inline_info.GetDexPc() == static_cast<uint32_t>(-1)) {
-    // "charAt" special case. It is the only non-leaf method we inline across dex files.
-    ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
-    DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index);
-    return inlined_method;
+    if (inline_info.EncodesArtMethod()) {
+      return inline_info.GetArtMethod();
+    }
+
+    uint32_t method_index = inline_info.GetMethodIndex(method_info);
+    if (inline_info.GetDexPc() == static_cast<uint32_t>(-1)) {
+      // "charAt" special case. It is the only non-leaf method we inline across dex files.
+      ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
+      DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index);
+      return inlined_method;
+    }
   }
 
   // Find which method did the call in the inlining hierarchy.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ArtMethod* method = outer_method;
-  for (uint32_t depth = 0, end = inlining_depth + 1u; depth != end; ++depth) {
-    inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth);
+  for (InlineInfo inline_info : inline_infos) {
     DCHECK(!inline_info.EncodesArtMethod());
     DCHECK_NE(inline_info.GetDexPc(), static_cast<uint32_t>(-1));
-    method_index = inline_info.GetMethodIndex(method_info);
+    uint32_t method_index = inline_info.GetMethodIndex(method_info);
     ArtMethod* inlined_method = class_linker->LookupResolvedMethod(method_index,
                                                                    method->GetDexCache(),
                                                                    method->GetClassLoader());
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index e71d1fa..9e6c642 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -205,9 +205,9 @@
       MethodInfo method_info = current_code->GetOptimizedMethodInfo();
       StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
       DCHECK(stack_map.IsValid());
-      uint32_t depth = code_info.GetInlineDepthOf(stack_map);
-      if (depth != 0) {
-        caller = GetResolvedMethod(outer_method, method_info, code_info, stack_map, depth - 1);
+      BitTableRange<InlineInfo> inline_infos = code_info.GetInlineInfosOf(stack_map);
+      if (!inline_infos.empty()) {
+        caller = GetResolvedMethod(outer_method, method_info, inline_infos);
       }
     }
     if (kIsDebugBuild && do_caller_check) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 3ccfa55..c894406 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -345,10 +345,9 @@
       CodeInfo code_info(current_code);
       StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset);
       DCHECK(stack_map.IsValid());
-      uint32_t depth = code_info.GetInlineDepthOf(stack_map);
-      if (depth != 0) {
-        InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth - 1);
-        return inline_info.GetDexPc();
+      BitTableRange<InlineInfo> inline_infos = code_info.GetInlineInfosOf(stack_map);
+      if (!inline_infos.empty()) {
+        return inline_infos.back().GetDexPc();
       } else {
         return stack_map.GetDexPc();
       }
@@ -1236,37 +1235,35 @@
   LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(outer_method, dex_pc);
 
   ArtMethod* caller = outer_method;
-  uint32_t depth = code_info.GetInlineDepthOf(stack_map);
-  if (depth != 0) {
-    for (size_t d = 0; d < depth; ++d) {
-      InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, d);
-      const char* tag = "";
-      dex_pc = inline_info.GetDexPc();
-      if (inline_info.EncodesArtMethod()) {
-        tag = "encoded ";
-        caller = inline_info.GetArtMethod();
+  BitTableRange<InlineInfo> inline_infos = code_info.GetInlineInfosOf(stack_map);
+  for (InlineInfo inline_info : inline_infos) {
+    const char* tag = "";
+    dex_pc = inline_info.GetDexPc();
+    if (inline_info.EncodesArtMethod()) {
+      tag = "encoded ";
+      caller = inline_info.GetArtMethod();
+    } else {
+      uint32_t method_index = inline_info.GetMethodIndex(method_info);
+      if (dex_pc == static_cast<uint32_t>(-1)) {
+        tag = "special ";
+        CHECK(inline_info.Equals(inline_infos.back()));
+        caller = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
+        CHECK_EQ(caller->GetDexMethodIndex(), method_index);
       } else {
-        uint32_t method_index = inline_info.GetMethodIndex(method_info);
-        if (dex_pc == static_cast<uint32_t>(-1)) {
-          tag = "special ";
-          CHECK_EQ(d + 1u, depth);
-          caller = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt);
-          CHECK_EQ(caller->GetDexMethodIndex(), method_index);
-        } else {
-          ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache();
-          ObjPtr<mirror::ClassLoader> class_loader = caller->GetClassLoader();
-          caller = class_linker->LookupResolvedMethod(method_index, dex_cache, class_loader);
-          CHECK(caller != nullptr);
-        }
+        ObjPtr<mirror::DexCache> dex_cache = caller->GetDexCache();
+        ObjPtr<mirror::ClassLoader> class_loader = caller->GetClassLoader();
+        caller = class_linker->LookupResolvedMethod(method_index, dex_cache, class_loader);
+        CHECK(caller != nullptr);
       }
-      LOG(FATAL_WITHOUT_ABORT) << "Inlined method #" << d << ": " << tag << caller->PrettyMethod()
-          << " dex pc: " << dex_pc
-          << " dex file: " << caller->GetDexFile()->GetLocation()
-          << " class table: "
-          << class_linker->ClassTableForClassLoader(caller->GetClassLoader());
-      DumpB74410240ClassData(caller->GetDeclaringClass());
-      LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(caller, dex_pc);
     }
+    LOG(FATAL_WITHOUT_ABORT) << "InlineInfo #" << inline_info.Row()
+        << ": " << tag << caller->PrettyMethod()
+        << " dex pc: " << dex_pc
+        << " dex file: " << caller->GetDexFile()->GetLocation()
+        << " class table: "
+        << class_linker->ClassTableForClassLoader(caller->GetClassLoader());
+    DumpB74410240ClassData(caller->GetDeclaringClass());
+    LOG(FATAL_WITHOUT_ABORT) << "  instruction: " << DumpInstruction(caller, dex_pc);
   }
 }
 
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 8b99b9f..28fcd87 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -404,7 +404,7 @@
     uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map);
     BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
     DexRegisterMap vreg_map = IsInInlinedFrame()
-        ? code_info.GetDexRegisterMapAtDepth(GetCurrentInliningDepth() - 1, stack_map)
+        ? code_info.GetInlineDexRegisterMapOf(stack_map, GetCurrentInlinedFrame())
         : code_info.GetDexRegisterMapOf(stack_map);
     if (vreg_map.empty()) {
       return;
diff --git a/runtime/stack.cc b/runtime/stack.cc
index a181bfe..97d077f 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -68,7 +68,6 @@
       cur_oat_quick_method_header_(nullptr),
       num_frames_(num_frames),
       cur_depth_(0),
-      current_inlining_depth_(0),
       context_(context),
       check_suspended_(check_suspended) {
   if (check_suspended_) {
@@ -76,32 +75,15 @@
   }
 }
 
-static StackMap GetCurrentStackMap(CodeInfo& code_info,
-                                   const OatQuickMethodHeader* method_header,
-                                   uintptr_t cur_quick_frame_pc)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc);
-  StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
-  DCHECK(stack_map.IsValid());
-  return stack_map;
-}
-
 ArtMethod* StackVisitor::GetMethod() const {
   if (cur_shadow_frame_ != nullptr) {
     return cur_shadow_frame_->GetMethod();
   } else if (cur_quick_frame_ != nullptr) {
     if (IsInInlinedFrame()) {
-      size_t depth_in_stack_map = current_inlining_depth_ - 1;
       const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
-      CodeInfo code_info(method_header);
-      StackMap stack_map = GetCurrentStackMap(code_info, method_header, cur_quick_frame_pc_);
       MethodInfo method_info = method_header->GetOptimizedMethodInfo();
       DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames);
-      return GetResolvedMethod(*GetCurrentQuickFrame(),
-                               method_info,
-                               code_info,
-                               stack_map,
-                               depth_in_stack_map);
+      return GetResolvedMethod(*GetCurrentQuickFrame(), method_info, current_inline_frames_);
     } else {
       return *cur_quick_frame_;
     }
@@ -114,11 +96,7 @@
     return cur_shadow_frame_->GetDexPC();
   } else if (cur_quick_frame_ != nullptr) {
     if (IsInInlinedFrame()) {
-      const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
-      CodeInfo code_info(method_header);
-      size_t depth_in_stack_map = current_inlining_depth_ - 1;
-      StackMap stack_map = GetCurrentStackMap(code_info, method_header, cur_quick_frame_pc_);
-      return code_info.GetInlineInfoAtDepth(stack_map, depth_in_stack_map).GetDexPc();
+      return current_inline_frames_.back().GetDexPc();
     } else if (cur_oat_quick_method_header_ == nullptr) {
       return dex::kDexNoIndex;
     } else {
@@ -233,10 +211,9 @@
   uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc_);
   StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
   DCHECK(stack_map.IsValid());
-  size_t depth_in_stack_map = current_inlining_depth_ - 1;
 
   DexRegisterMap dex_register_map = IsInInlinedFrame()
-      ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map, stack_map)
+      ? code_info.GetInlineDexRegisterMapOf(stack_map, current_inline_frames_.back())
       : code_info.GetDexRegisterMapOf(stack_map);
   if (dex_register_map.empty()) {
     return false;
@@ -820,10 +797,10 @@
               cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_);
           StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
           if (stack_map.IsValid() && stack_map.HasInlineInfo()) {
-            DCHECK_EQ(current_inlining_depth_, 0u);
-            for (current_inlining_depth_ = code_info.GetInlineDepthOf(stack_map);
-                 current_inlining_depth_ != 0;
-                 --current_inlining_depth_) {
+            DCHECK_EQ(current_inline_frames_.size(), 0u);
+            for (current_inline_frames_ = code_info.GetInlineInfosOf(stack_map);
+                 !current_inline_frames_.empty();
+                 current_inline_frames_.pop_back()) {
               bool should_continue = VisitFrame();
               if (UNLIKELY(!should_continue)) {
                 return;
diff --git a/runtime/stack.h b/runtime/stack.h
index a16930b..02578d2 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "quick/quick_method_frame_info.h"
+#include "stack_map.h"
 
 namespace art {
 
@@ -219,11 +220,11 @@
   void SetReturnPc(uintptr_t new_ret_pc) REQUIRES_SHARED(Locks::mutator_lock_);
 
   bool IsInInlinedFrame() const {
-    return current_inlining_depth_ != 0;
+    return !current_inline_frames_.empty();
   }
 
-  size_t GetCurrentInliningDepth() const {
-    return current_inlining_depth_;
+  InlineInfo GetCurrentInlinedFrame() const {
+    return current_inline_frames_.back();
   }
 
   uintptr_t GetCurrentQuickFramePc() const {
@@ -309,9 +310,9 @@
   size_t num_frames_;
   // Depth of the frame we're currently at.
   size_t cur_depth_;
-  // Current inlining depth of the method we are currently at.
-  // 0 if there is no inlined frame.
-  size_t current_inlining_depth_;
+  // Current inlined frames of the method we are currently at.
+  // We keep poping frames from the end as we visit the frames.
+  BitTableRange<InlineInfo> current_inline_frames_;
 
  protected:
   Context* const context_;
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index a3c6e05..7e46eb7 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -232,8 +232,7 @@
 
   // Display stack maps along with (live) Dex register maps.
   if (verbose) {
-    for (size_t i = 0; i < GetNumberOfStackMaps(); ++i) {
-      StackMap stack_map = GetStackMapAt(i);
+    for (StackMap stack_map : stack_maps_) {
       stack_map.Dump(vios, *this, method_info, code_offset, instruction_set);
     }
   }
@@ -259,9 +258,7 @@
   }
   vios->Stream() << ")\n";
   code_info.GetDexRegisterMapOf(*this).Dump(vios);
-  uint32_t depth = code_info.GetInlineDepthOf(*this);
-  for (size_t d = 0; d < depth; d++) {
-    InlineInfo inline_info = code_info.GetInlineInfoAtDepth(*this, d);
+  for (InlineInfo inline_info : code_info.GetInlineInfosOf(*this)) {
     inline_info.Dump(vios, code_info, *this, method_info);
   }
 }
@@ -285,7 +282,7 @@
         << ", method_index=" << GetMethodIndex(method_info);
   }
   vios->Stream() << ")\n";
-  code_info.GetDexRegisterMapAtDepth(depth, stack_map).Dump(vios);
+  code_info.GetInlineDexRegisterMapOf(stack_map, *this).Dump(vios);
 }
 
 }  // namespace art
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index ad52f37..2f2053a 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -298,8 +298,8 @@
     return BitsToBytesRoundUp(size_in_bits_);
   }
 
-  bool HasInlineInfo() const {
-    return inline_infos_.NumRows() > 0;
+  ALWAYS_INLINE const BitTable<StackMap>& GetStackMaps() const {
+    return stack_maps_;
   }
 
   ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const {
@@ -330,6 +330,10 @@
       : dex_register_catalog_.GetRow(index).GetLocation();
   }
 
+  bool HasInlineInfo() const {
+    return inline_infos_.NumRows() > 0;
+  }
+
   uint32_t GetNumberOfStackMaps() const {
     return stack_maps_.NumRows();
   }
@@ -347,14 +351,18 @@
     return DexRegisterMap(0, DexRegisterLocation::None());
   }
 
-  ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, StackMap stack_map) const {
+  ALWAYS_INLINE DexRegisterMap GetInlineDexRegisterMapOf(StackMap stack_map,
+                                                         InlineInfo inline_info) const {
     if (stack_map.HasDexRegisterMap()) {
+      DCHECK(stack_map.HasInlineInfoIndex());
+      uint32_t depth = inline_info.Row() - stack_map.GetInlineInfoIndex();
       // The register counts are commutative and include all outer levels.
       // This allows us to determine the range [first, last) in just two lookups.
       // If we are at depth 0 (the first inlinee), the count from the main method is used.
-      uint32_t first = (depth == 0) ? number_of_dex_registers_
-          : GetInlineInfoAtDepth(stack_map, depth - 1).GetNumberOfDexRegisters();
-      uint32_t last = GetInlineInfoAtDepth(stack_map, depth).GetNumberOfDexRegisters();
+      uint32_t first = (depth == 0)
+          ? number_of_dex_registers_
+          : inline_infos_.GetRow(inline_info.Row() - 1).GetNumberOfDexRegisters();
+      uint32_t last = inline_info.GetNumberOfDexRegisters();
       DexRegisterMap map(last - first, DexRegisterLocation::Invalid());
       DecodeDexRegisterMap(stack_map.Row(), first, &map);
       return map;
@@ -362,28 +370,20 @@
     return DexRegisterMap(0, DexRegisterLocation::None());
   }
 
-  InlineInfo GetInlineInfo(size_t index) const {
-    return inline_infos_.GetRow(index);
-  }
-
-  uint32_t GetInlineDepthOf(StackMap stack_map) const {
-    uint32_t depth = 0;
+  BitTableRange<InlineInfo> GetInlineInfosOf(StackMap stack_map) const {
     uint32_t index = stack_map.GetInlineInfoIndex();
     if (index != StackMap::kNoValue) {
-      while (GetInlineInfo(index + depth++).GetIsLast() == InlineInfo::kMore) { }
+      auto begin = inline_infos_.begin() + index;
+      auto end = begin;
+      while ((*end++).GetIsLast() == InlineInfo::kMore) { }
+      return BitTableRange<InlineInfo>(begin, end);
+    } else {
+      return BitTableRange<InlineInfo>();
     }
-    return depth;
-  }
-
-  InlineInfo GetInlineInfoAtDepth(StackMap stack_map, uint32_t depth) const {
-    DCHECK(stack_map.HasInlineInfo());
-    DCHECK_LT(depth, GetInlineDepthOf(stack_map));
-    return GetInlineInfo(stack_map.GetInlineInfoIndex() + depth);
   }
 
   StackMap GetStackMapForDexPc(uint32_t dex_pc) const {
-    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
-      StackMap stack_map = GetStackMapAt(i);
+    for (StackMap stack_map : stack_maps_) {
       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() != StackMap::Kind::Debug) {
         return stack_map;
       }
@@ -403,8 +403,7 @@
   }
 
   StackMap GetOsrStackMapForDexPc(uint32_t dex_pc) const {
-    for (size_t i = 0, e = GetNumberOfStackMaps(); i < e; ++i) {
-      StackMap stack_map = GetStackMapAt(i);
+    for (StackMap stack_map : stack_maps_) {
       if (stack_map.GetDexPc() == dex_pc && stack_map.GetKind() == StackMap::Kind::OSR) {
         return stack_map;
       }
@@ -415,8 +414,7 @@
   StackMap GetStackMapForNativePcOffset(uint32_t pc, InstructionSet isa = kRuntimeISA) const;
 
   InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset) {
-    for (size_t index = 0; index < invoke_infos_.NumRows(); index++) {
-      InvokeInfo item = GetInvokeInfo(index);
+    for (InvokeInfo item : invoke_infos_) {
       if (item.GetNativePcOffset(kRuntimeISA) == native_pc_offset) {
         return item;
       }