Merge "Revert "Refactor HGraphBuilder and SsaBuilder to remove HLocals""
diff --git a/compiler/optimizing/common_arm64.h b/compiler/optimizing/common_arm64.h
index 6c55194..6412b24 100644
--- a/compiler/optimizing/common_arm64.h
+++ b/compiler/optimizing/common_arm64.h
@@ -53,17 +53,17 @@
 }
 
 static inline vixl::Register XRegisterFrom(Location location) {
-  DCHECK(location.IsRegister());
+  DCHECK(location.IsRegister()) << location;
   return vixl::Register::XRegFromCode(VIXLRegCodeFromART(location.reg()));
 }
 
 static inline vixl::Register WRegisterFrom(Location location) {
-  DCHECK(location.IsRegister());
+  DCHECK(location.IsRegister()) << location;
   return vixl::Register::WRegFromCode(VIXLRegCodeFromART(location.reg()));
 }
 
 static inline vixl::Register RegisterFrom(Location location, Primitive::Type type) {
-  DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type));
+  DCHECK(type != Primitive::kPrimVoid && !Primitive::IsFloatingPointType(type)) << type;
   return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location);
 }
 
@@ -77,17 +77,17 @@
 }
 
 static inline vixl::FPRegister DRegisterFrom(Location location) {
-  DCHECK(location.IsFpuRegister());
+  DCHECK(location.IsFpuRegister()) << location;
   return vixl::FPRegister::DRegFromCode(location.reg());
 }
 
 static inline vixl::FPRegister SRegisterFrom(Location location) {
-  DCHECK(location.IsFpuRegister());
+  DCHECK(location.IsFpuRegister()) << location;
   return vixl::FPRegister::SRegFromCode(location.reg());
 }
 
 static inline vixl::FPRegister FPRegisterFrom(Location location, Primitive::Type type) {
-  DCHECK(Primitive::IsFloatingPointType(type));
+  DCHECK(Primitive::IsFloatingPointType(type)) << type;
   return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location);
 }
 
@@ -124,7 +124,7 @@
   } else if (instr->IsNullConstant()) {
     return 0;
   } else {
-    DCHECK(instr->IsLongConstant());
+    DCHECK(instr->IsLongConstant()) << instr->DebugName();
     return instr->AsLongConstant()->GetValue();
   }
 }
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index e3172df..d936a8c 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1061,14 +1061,19 @@
       caller_instruction_counter);
   callee_graph->SetArtMethod(resolved_method);
 
-  OptimizingCompilerStats inline_stats;
+  // When they are needed, allocate `inline_stats` on the heap instead
+  // of on the stack, as Clang might produce a stack frame too large
+  // for this function, that would not fit the requirements of the
+  // `-Wframe-larger-than` option.
+  std::unique_ptr<OptimizingCompilerStats> inline_stats =
+      (stats_ == nullptr) ? nullptr : MakeUnique<OptimizingCompilerStats>();
   HGraphBuilder builder(callee_graph,
                         &dex_compilation_unit,
                         &outer_compilation_unit_,
                         resolved_method->GetDexFile(),
                         *code_item,
                         compiler_driver_,
-                        &inline_stats,
+                        inline_stats.get(),
                         resolved_method->GetQuickenedInfo(),
                         dex_cache);
 
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 5de2306..a589ef0 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -368,17 +368,16 @@
   GenReverse(invoke->GetLocations(), Primitive::kPrimLong, GetVIXLAssembler());
 }
 
-static void GenBitCount(HInvoke* instr, bool is_long, vixl::MacroAssembler* masm) {
-  DCHECK(instr->GetType() == Primitive::kPrimInt);
-  DCHECK((is_long && instr->InputAt(0)->GetType() == Primitive::kPrimLong) ||
-         (!is_long && instr->InputAt(0)->GetType() == Primitive::kPrimInt));
+static void GenBitCount(HInvoke* instr, Primitive::Type type, vixl::MacroAssembler* masm) {
+  DCHECK(Primitive::IsIntOrLongType(type)) << type;
+  DCHECK_EQ(instr->GetType(), Primitive::kPrimInt);
+  DCHECK_EQ(Primitive::PrimitiveKind(instr->InputAt(0)->GetType()), type);
 
-  Location out = instr->GetLocations()->Out();
   UseScratchRegisterScope temps(masm);
 
   Register src = InputRegisterAt(instr, 0);
-  Register dst = is_long ? XRegisterFrom(out) : WRegisterFrom(out);
-  FPRegister fpr = is_long ? temps.AcquireD() : temps.AcquireS();
+  Register dst = RegisterFrom(instr->GetLocations()->Out(), type);
+  FPRegister fpr = (type == Primitive::kPrimLong) ? temps.AcquireD() : temps.AcquireS();
 
   __ Fmov(fpr, src);
   __ Cnt(fpr.V8B(), fpr.V8B());
@@ -391,7 +390,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, /* is_long */ true, GetVIXLAssembler());
+  GenBitCount(invoke, Primitive::kPrimLong, GetVIXLAssembler());
 }
 
 void IntrinsicLocationsBuilderARM64::VisitIntegerBitCount(HInvoke* invoke) {
@@ -399,7 +398,7 @@
 }
 
 void IntrinsicCodeGeneratorARM64::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(invoke, /* is_long */ false, GetVIXLAssembler());
+  GenBitCount(invoke, Primitive::kPrimInt, GetVIXLAssembler());
 }
 
 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 1280587..19c6a22 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -614,8 +614,6 @@
                         Primitive::Type type,
                         bool isR6,
                         MipsAssembler* assembler) {
-  DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
-
   Register out = locations->Out().AsRegister<Register>();
 
   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
@@ -663,7 +661,8 @@
       __ MulR2(out, out, TMP);
     }
     __ Srl(out, out, 24);
-  } else if (type == Primitive::kPrimLong) {
+  } else {
+    DCHECK_EQ(type, Primitive::kPrimLong);
     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
     Register tmp_hi = locations->GetTemp(0).AsRegister<Register>();
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 95fdb9b..4aab3e2 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2387,10 +2387,10 @@
   if (invoke->InputAt(0)->IsConstant()) {
     // Evaluate this at compile time.
     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
-    value = is_long
+    int32_t result = is_long
         ? POPCOUNT(static_cast<uint64_t>(value))
         : POPCOUNT(static_cast<uint32_t>(value));
-    codegen->Load32BitValue(out, value);
+    codegen->Load32BitValue(out, result);
     return;
   }
 
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 9e568f7..9ca4ef0 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2402,10 +2402,10 @@
   if (invoke->InputAt(0)->IsConstant()) {
     // Evaluate this at compile time.
     int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
-    value = is_long
+    int32_t result = is_long
         ? POPCOUNT(static_cast<uint64_t>(value))
         : POPCOUNT(static_cast<uint32_t>(value));
-    codegen->Load32BitValue(out, value);
+    codegen->Load32BitValue(out, result);
     return;
   }
 
diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc
index c571312..11a254e 100644
--- a/compiler/optimizing/stack_map_stream.cc
+++ b/compiler/optimizing/stack_map_stream.cc
@@ -137,8 +137,9 @@
 
 size_t StackMapStream::PrepareForFillIn() {
   int stack_mask_number_of_bits = stack_mask_max_ + 1;  // Need room for max element too.
-  inline_info_size_ = ComputeInlineInfoSize();
   dex_register_maps_size_ = ComputeDexRegisterMapsSize();
+  ComputeInlineInfoEncoding();  // needs dex_register_maps_size_.
+  inline_info_size_ = inline_infos_.size() * inline_info_encoding_.GetEntrySize();
   uint32_t max_native_pc_offset = ComputeMaxNativePcOffset();
   size_t stack_map_size = stack_map_encoding_.SetFromSizes(max_native_pc_offset,
                                                            dex_pc_max_,
@@ -158,9 +159,10 @@
   // Prepare the CodeInfo variable-sized encoding.
   CodeInfoEncoding code_info_encoding;
   code_info_encoding.non_header_size = non_header_size;
-  code_info_encoding.stack_map_encoding = stack_map_encoding_;
   code_info_encoding.number_of_stack_maps = stack_maps_.size();
   code_info_encoding.stack_map_size_in_bytes = stack_map_size;
+  code_info_encoding.stack_map_encoding = stack_map_encoding_;
+  code_info_encoding.inline_info_encoding = inline_info_encoding_;
   code_info_encoding.number_of_location_catalog_entries = location_catalog_entries_.size();
   code_info_encoding.Compress(&code_info_encoding_);
 
@@ -224,10 +226,26 @@
   return size;
 }
 
-size_t StackMapStream::ComputeInlineInfoSize() const {
-  return inline_infos_.size() * InlineInfo::SingleEntrySize()
-    // For encoding the depth.
-    + (number_of_stack_maps_with_inline_info_ * InlineInfo::kFixedSize);
+void StackMapStream::ComputeInlineInfoEncoding() {
+  uint32_t method_index_max = 0;
+  uint32_t dex_pc_max = 0;
+  uint32_t invoke_type_max = 0;
+
+  uint32_t inline_info_index = 0;
+  for (const StackMapEntry& entry : stack_maps_) {
+    for (size_t j = 0; j < entry.inlining_depth; ++j) {
+      InlineInfoEntry inline_entry = inline_infos_[inline_info_index++];
+      method_index_max = std::max(method_index_max, inline_entry.method_index);
+      dex_pc_max = std::max(dex_pc_max, inline_entry.dex_pc);
+      invoke_type_max = std::max(invoke_type_max, static_cast<uint32_t>(inline_entry.invoke_type));
+    }
+  }
+  DCHECK_EQ(inline_info_index, inline_infos_.size());
+
+  inline_info_encoding_.SetFromSizes(method_index_max,
+                                     dex_pc_max,
+                                     invoke_type_max,
+                                     dex_register_maps_size_);
 }
 
 void StackMapStream::FillIn(MemoryRegion region) {
@@ -321,7 +339,7 @@
     if (entry.inlining_depth != 0) {
       MemoryRegion inline_region = inline_infos_region.Subregion(
           next_inline_info_offset,
-          InlineInfo::kFixedSize + entry.inlining_depth * InlineInfo::SingleEntrySize());
+          entry.inlining_depth * inline_info_encoding_.GetEntrySize());
       next_inline_info_offset += inline_region.size();
       InlineInfo inline_info(inline_region);
 
@@ -329,16 +347,18 @@
       stack_map.SetInlineDescriptorOffset(
           stack_map_encoding_, inline_region.start() - dex_register_locations_region.start());
 
-      inline_info.SetDepth(entry.inlining_depth);
+      inline_info.SetDepth(inline_info_encoding_, entry.inlining_depth);
       DCHECK_LE(entry.inline_infos_start_index + entry.inlining_depth, inline_infos_.size());
       for (size_t depth = 0; depth < entry.inlining_depth; ++depth) {
         InlineInfoEntry inline_entry = inline_infos_[depth + entry.inline_infos_start_index];
-        inline_info.SetMethodIndexAtDepth(depth, inline_entry.method_index);
-        inline_info.SetDexPcAtDepth(depth, inline_entry.dex_pc);
-        inline_info.SetInvokeTypeAtDepth(depth, inline_entry.invoke_type);
+        inline_info.SetMethodIndexAtDepth(inline_info_encoding_, depth, inline_entry.method_index);
+        inline_info.SetDexPcAtDepth(inline_info_encoding_, depth, inline_entry.dex_pc);
+        inline_info.SetInvokeTypeAtDepth(inline_info_encoding_, depth, inline_entry.invoke_type);
         if (inline_entry.num_dex_registers == 0) {
           // No dex map available.
-          inline_info.SetDexRegisterMapOffsetAtDepth(depth, StackMap::kNoDexRegisterMap);
+          inline_info.SetDexRegisterMapOffsetAtDepth(inline_info_encoding_,
+                                                     depth,
+                                                     StackMap::kNoDexRegisterMap);
           DCHECK(inline_entry.live_dex_registers_mask == nullptr);
         } else {
           MemoryRegion register_region = dex_register_locations_region.Subregion(
@@ -348,7 +368,8 @@
           next_dex_register_map_offset += register_region.size();
           DexRegisterMap dex_register_map(register_region);
           inline_info.SetDexRegisterMapOffsetAtDepth(
-            depth, register_region.start() - dex_register_locations_region.start());
+              inline_info_encoding_,
+              depth, register_region.start() - dex_register_locations_region.start());
 
           FillInDexRegisterMap(dex_register_map,
                                inline_entry.num_dex_registers,
@@ -513,14 +534,17 @@
     DCHECK_EQ(stack_map.HasInlineInfo(stack_map_encoding), (entry.inlining_depth != 0));
     if (entry.inlining_depth != 0) {
       InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
-      DCHECK_EQ(inline_info.GetDepth(), entry.inlining_depth);
+      DCHECK_EQ(inline_info.GetDepth(encoding.inline_info_encoding), entry.inlining_depth);
       for (size_t d = 0; d < entry.inlining_depth; ++d) {
         size_t inline_info_index = entry.inline_infos_start_index + d;
         DCHECK_LT(inline_info_index, inline_infos_.size());
         InlineInfoEntry inline_entry = inline_infos_[inline_info_index];
-        DCHECK_EQ(inline_info.GetDexPcAtDepth(d), inline_entry.dex_pc);
-        DCHECK_EQ(inline_info.GetMethodIndexAtDepth(d), inline_entry.method_index);
-        DCHECK_EQ(inline_info.GetInvokeTypeAtDepth(d), inline_entry.invoke_type);
+        DCHECK_EQ(inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, d),
+                  inline_entry.dex_pc);
+        DCHECK_EQ(inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, d),
+                  inline_entry.method_index);
+        DCHECK_EQ(inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, d),
+                  inline_entry.invoke_type);
 
         CheckDexRegisterMap(code_info,
                             code_info.GetDexRegisterMapAtDepth(
diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h
index b686748..41f72f5 100644
--- a/compiler/optimizing/stack_map_stream.h
+++ b/compiler/optimizing/stack_map_stream.h
@@ -156,7 +156,7 @@
   size_t ComputeDexRegisterMapSize(uint32_t num_dex_registers,
                                    const BitVector* live_dex_registers_mask) const;
   size_t ComputeDexRegisterMapsSize() const;
-  size_t ComputeInlineInfoSize() const;
+  void ComputeInlineInfoEncoding();
 
   // Returns the index of an entry with the same dex register map as the current_entry,
   // or kNoSameDexMapFound if no such entry exists.
@@ -200,6 +200,7 @@
   StackMapEntry current_entry_;
   InlineInfoEntry current_inline_info_;
   StackMapEncoding stack_map_encoding_;
+  InlineInfoEncoding inline_info_encoding_;
   ArenaVector<uint8_t> code_info_encoding_;
   size_t inline_info_size_;
   size_t dex_register_maps_size_;
diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc
index 3552487..967fd96 100644
--- a/compiler/optimizing/stack_map_test.cc
+++ b/compiler/optimizing/stack_map_test.cc
@@ -237,13 +237,13 @@
 
     ASSERT_TRUE(stack_map.HasInlineInfo(encoding.stack_map_encoding));
     InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
-    ASSERT_EQ(2u, inline_info.GetDepth());
-    ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(0));
-    ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(1));
-    ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0));
-    ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1));
-    ASSERT_EQ(kDirect, inline_info.GetInvokeTypeAtDepth(0));
-    ASSERT_EQ(kStatic, inline_info.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(2u, inline_info.GetDepth(encoding.inline_info_encoding));
+    ASSERT_EQ(82u, inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(42u, inline_info.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(kDirect, inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(kStatic, inline_info.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
   }
 
   // Second stack map.
@@ -741,13 +741,13 @@
     ASSERT_EQ(4, dex_registers0.GetConstant(1, 2, ci, encoding));
 
     InlineInfo if0 = ci.GetInlineInfoOf(sm0, encoding);
-    ASSERT_EQ(2u, if0.GetDepth());
-    ASSERT_EQ(2u, if0.GetDexPcAtDepth(0));
-    ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(0));
-    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(0));
-    ASSERT_EQ(3u, if0.GetDexPcAtDepth(1));
-    ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(1));
-    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(1));
+    ASSERT_EQ(2u, if0.GetDepth(encoding.inline_info_encoding));
+    ASSERT_EQ(2u, if0.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(42u, if0.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(3u, if0.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(82u, if0.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(kStatic, if0.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
 
     DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, encoding, 1);
     ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
@@ -767,16 +767,16 @@
     ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding));
 
     InlineInfo if1 = ci.GetInlineInfoOf(sm1, encoding);
-    ASSERT_EQ(3u, if1.GetDepth());
-    ASSERT_EQ(2u, if1.GetDexPcAtDepth(0));
-    ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(0));
-    ASSERT_EQ(kDirect, if1.GetInvokeTypeAtDepth(0));
-    ASSERT_EQ(3u, if1.GetDexPcAtDepth(1));
-    ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(1));
-    ASSERT_EQ(kStatic, if1.GetInvokeTypeAtDepth(1));
-    ASSERT_EQ(5u, if1.GetDexPcAtDepth(2));
-    ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(2));
-    ASSERT_EQ(kVirtual, if1.GetInvokeTypeAtDepth(2));
+    ASSERT_EQ(3u, if1.GetDepth(encoding.inline_info_encoding));
+    ASSERT_EQ(2u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(42u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(kDirect, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(3u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(82u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(kStatic, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(5u, if1.GetDexPcAtDepth(encoding.inline_info_encoding, 2));
+    ASSERT_EQ(52u, if1.GetMethodIndexAtDepth(encoding.inline_info_encoding, 2));
+    ASSERT_EQ(kVirtual, if1.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 2));
 
     DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, encoding, 1);
     ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0, 1, ci, encoding));
@@ -786,7 +786,7 @@
     ASSERT_EQ(10, dex_registers2.GetConstant(1, 3, ci, encoding));
     ASSERT_EQ(5, dex_registers2.GetMachineRegister(2, 3, ci, encoding));
 
-    ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2));
+    ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, 2));
   }
 
   {
@@ -808,18 +808,18 @@
     ASSERT_EQ(0, dex_registers0.GetConstant(1, 2, ci, encoding));
 
     InlineInfo if2 = ci.GetInlineInfoOf(sm3, encoding);
-    ASSERT_EQ(3u, if2.GetDepth());
-    ASSERT_EQ(2u, if2.GetDexPcAtDepth(0));
-    ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(0));
-    ASSERT_EQ(kVirtual, if2.GetInvokeTypeAtDepth(0));
-    ASSERT_EQ(5u, if2.GetDexPcAtDepth(1));
-    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(1));
-    ASSERT_EQ(kInterface, if2.GetInvokeTypeAtDepth(1));
-    ASSERT_EQ(10u, if2.GetDexPcAtDepth(2));
-    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(2));
-    ASSERT_EQ(kStatic, if2.GetInvokeTypeAtDepth(2));
+    ASSERT_EQ(3u, if2.GetDepth(encoding.inline_info_encoding));
+    ASSERT_EQ(2u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(42u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(kVirtual, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 0));
+    ASSERT_EQ(5u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(kInterface, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 1));
+    ASSERT_EQ(10u, if2.GetDexPcAtDepth(encoding.inline_info_encoding, 2));
+    ASSERT_EQ(52u, if2.GetMethodIndexAtDepth(encoding.inline_info_encoding, 2));
+    ASSERT_EQ(kStatic, if2.GetInvokeTypeAtDepth(encoding.inline_info_encoding, 2));
 
-    ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0));
+    ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, 0));
 
     DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, encoding, 1);
     ASSERT_EQ(2, dex_registers1.GetMachineRegister(0, 1, ci, encoding));
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 116261b..16fbfaa 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -42,11 +42,12 @@
 template <bool kResolve = true>
 inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
                                     const InlineInfo& inline_info,
+                                    const InlineInfoEncoding& encoding,
                                     uint8_t inlining_depth)
   SHARED_REQUIRES(Locks::mutator_lock_) {
-  uint32_t method_index = inline_info.GetMethodIndexAtDepth(inlining_depth);
+  uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth);
   InvokeType invoke_type = static_cast<InvokeType>(
-        inline_info.GetInvokeTypeAtDepth(inlining_depth));
+        inline_info.GetInvokeTypeAtDepth(encoding, inlining_depth));
   ArtMethod* caller = outer_method->GetDexCacheResolvedMethod(method_index, sizeof(void*));
   if (!caller->IsRuntimeMethod()) {
     return caller;
@@ -68,7 +69,10 @@
   if (inlining_depth == 0) {
     class_loader.Assign(outer_method->GetClassLoader());
   } else {
-    caller = GetResolvedMethod<kResolve>(outer_method, inline_info, inlining_depth - 1);
+    caller = GetResolvedMethod<kResolve>(outer_method,
+                                         inline_info,
+                                         encoding,
+                                         inlining_depth - 1);
     class_loader.Assign(caller->GetClassLoader());
   }
 
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 3368411..e46576e 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -280,7 +280,10 @@
         DCHECK(stack_map.IsValid());
         if (stack_map.HasInlineInfo(encoding.stack_map_encoding)) {
           InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
-          caller = GetResolvedMethod(outer_method, inline_info, inline_info.GetDepth() - 1);
+          caller = GetResolvedMethod(outer_method,
+                                     inline_info,
+                                     encoding.inline_info_encoding,
+                                     inline_info.GetDepth(encoding.inline_info_encoding) - 1);
         }
       }
     }
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 1a96d0f..f3e8dba 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -332,7 +332,8 @@
       DCHECK(stack_map.IsValid());
       if (stack_map.HasInlineInfo(encoding.stack_map_encoding)) {
         InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
-        return inline_info.GetDexPcAtDepth(inline_info.GetDepth() - 1);
+        return inline_info.GetDexPcAtDepth(encoding.inline_info_encoding,
+                                           inline_info.GetDepth(encoding.inline_info_encoding)-1);
       } else {
         return stack_map.GetDexPc(encoding.stack_map_encoding);
       }
diff --git a/runtime/oat.h b/runtime/oat.h
index 68e71c4..469a65f 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '7', '7', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '7', '8', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 2336365..c22eb92 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -130,11 +130,19 @@
     if (IsInInlinedFrame()) {
       size_t depth_in_stack_map = current_inlining_depth_ - 1;
       InlineInfo inline_info = GetCurrentInlineInfo();
+      const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+      CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding();
       DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames);
       bool allow_resolve = walk_kind_ != StackWalkKind::kIncludeInlinedFramesNoResolve;
       return allow_resolve
-          ? GetResolvedMethod<true>(*GetCurrentQuickFrame(), inline_info, depth_in_stack_map)
-          : GetResolvedMethod<false>(*GetCurrentQuickFrame(), inline_info, depth_in_stack_map);
+          ? GetResolvedMethod<true>(*GetCurrentQuickFrame(),
+                                    inline_info,
+                                    encoding.inline_info_encoding,
+                                    depth_in_stack_map)
+          : GetResolvedMethod<false>(*GetCurrentQuickFrame(),
+                                     inline_info,
+                                     encoding.inline_info_encoding,
+                                     depth_in_stack_map);
     } else {
       return *cur_quick_frame_;
     }
@@ -148,7 +156,10 @@
   } else if (cur_quick_frame_ != nullptr) {
     if (IsInInlinedFrame()) {
       size_t depth_in_stack_map = current_inlining_depth_ - 1;
-      return GetCurrentInlineInfo().GetDexPcAtDepth(depth_in_stack_map);
+      const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
+      CodeInfoEncoding encoding = method_header->GetOptimizedCodeInfo().ExtractEncoding();
+      return GetCurrentInlineInfo().GetDexPcAtDepth(encoding.inline_info_encoding,
+                                                    depth_in_stack_map);
     } else if (cur_oat_quick_method_header_ == nullptr) {
       return DexFile::kDexNoIndex;
     } else {
@@ -875,7 +886,7 @@
           if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding.stack_map_encoding)) {
             InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
             DCHECK_EQ(current_inlining_depth_, 0u);
-            for (current_inlining_depth_ = inline_info.GetDepth();
+            for (current_inlining_depth_ = inline_info.GetDepth(encoding.inline_info_encoding);
                  current_inlining_depth_ != 0;
                  --current_inlining_depth_) {
               bool should_continue = VisitFrame();
diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc
index b51baf1..a7e7c21 100644
--- a/runtime/stack_map.cc
+++ b/runtime/stack_map.cc
@@ -101,6 +101,17 @@
       << ")\n";
 }
 
+void InlineInfoEncoding::Dump(VariableIndentationOutputStream* vios) const {
+  vios->Stream()
+      << "InlineInfoEncoding"
+      << " (method_index_bit_offset=" << static_cast<uint32_t>(kMethodIndexBitOffset)
+      << ", dex_pc_bit_offset=" << static_cast<uint32_t>(dex_pc_bit_offset_)
+      << ", invoke_type_bit_offset=" << static_cast<uint32_t>(invoke_type_bit_offset_)
+      << ", dex_register_map_bit_offset=" << static_cast<uint32_t>(dex_register_map_bit_offset_)
+      << ", total_bit_size=" << static_cast<uint32_t>(total_bit_size_)
+      << ")\n";
+}
+
 void CodeInfo::Dump(VariableIndentationOutputStream* vios,
                     uint32_t code_offset,
                     uint16_t number_of_dex_registers,
@@ -113,6 +124,9 @@
       << ")\n";
   ScopedIndentation indent1(vios);
   encoding.stack_map_encoding.Dump(vios);
+  if (HasInlineInfo(encoding)) {
+    encoding.inline_info_encoding.Dump(vios);
+  }
   // Display the Dex register location catalog.
   GetDexRegisterLocationCatalog(encoding).Dump(vios, *this);
   // Display stack maps along with (live) Dex register maps.
@@ -207,18 +221,22 @@
 void InlineInfo::Dump(VariableIndentationOutputStream* vios,
                       const CodeInfo& code_info,
                       uint16_t number_of_dex_registers[]) const {
-  vios->Stream() << "InlineInfo with depth " << static_cast<uint32_t>(GetDepth()) << "\n";
+  InlineInfoEncoding inline_info_encoding = code_info.ExtractEncoding().inline_info_encoding;
+  vios->Stream() << "InlineInfo with depth "
+                 << static_cast<uint32_t>(GetDepth(inline_info_encoding))
+                 << "\n";
 
-  for (size_t i = 0; i < GetDepth(); ++i) {
+  for (size_t i = 0; i < GetDepth(inline_info_encoding); ++i) {
     vios->Stream()
         << " At depth " << i
         << std::hex
-        << " (dex_pc=0x" << GetDexPcAtDepth(i)
+        << " (dex_pc=0x" << GetDexPcAtDepth(inline_info_encoding, i)
         << std::dec
-        << ", method_index=" << GetMethodIndexAtDepth(i)
-        << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(i))
+        << ", method_index=" << GetMethodIndexAtDepth(inline_info_encoding, i)
+        << ", invoke_type=" << static_cast<InvokeType>(GetInvokeTypeAtDepth(inline_info_encoding,
+                                                                            i))
         << ")\n";
-    if (HasDexRegisterMapAtDepth(i) && (number_of_dex_registers != nullptr)) {
+    if (HasDexRegisterMapAtDepth(inline_info_encoding, i) && (number_of_dex_registers != nullptr)) {
       CodeInfoEncoding encoding = code_info.ExtractEncoding();
       DexRegisterMap dex_register_map =
           code_info.GetDexRegisterMapAtDepth(i, *this, encoding, number_of_dex_registers[i]);
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 9e8884e..7c50f97 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -24,12 +24,6 @@
 
 namespace art {
 
-#define ELEMENT_BYTE_OFFSET_AFTER(PreviousElement) \
-  k ## PreviousElement ## Offset + sizeof(PreviousElement ## Type)
-
-#define ELEMENT_BIT_OFFSET_AFTER(PreviousElement) \
-  k ## PreviousElement ## BitOffset + PreviousElement ## BitSize
-
 class VariableIndentationOutputStream;
 
 // Size of a frame slot, in bytes.  This constant is a signed value,
@@ -888,102 +882,139 @@
   friend class StackMapStream;
 };
 
+class InlineInfoEncoding {
+ public:
+  void SetFromSizes(size_t method_index_max,
+                    size_t dex_pc_max,
+                    size_t invoke_type_max,
+                    size_t dex_register_map_size) {
+    total_bit_size_ = kMethodIndexBitOffset;
+    total_bit_size_ += MinimumBitsToStore(method_index_max);
+
+    dex_pc_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
+    total_bit_size_ += MinimumBitsToStore(1 /* kNoDexPc */ + dex_pc_max);
+
+    invoke_type_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
+    total_bit_size_ += MinimumBitsToStore(invoke_type_max);
+
+    // We also need +1 for kNoDexRegisterMap, but since the size is strictly
+    // greater than any offset we might try to encode, we already implicitly have it.
+    dex_register_map_bit_offset_ = dchecked_integral_cast<uint8_t>(total_bit_size_);
+    total_bit_size_ += MinimumBitsToStore(dex_register_map_size);
+  }
+
+  ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const {
+    return FieldEncoding(kMethodIndexBitOffset, dex_pc_bit_offset_);
+  }
+  ALWAYS_INLINE FieldEncoding GetDexPcEncoding() const {
+    return FieldEncoding(dex_pc_bit_offset_, invoke_type_bit_offset_, -1 /* min_value */);
+  }
+  ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const {
+    return FieldEncoding(invoke_type_bit_offset_, dex_register_map_bit_offset_);
+  }
+  ALWAYS_INLINE FieldEncoding GetDexRegisterMapEncoding() const {
+    return FieldEncoding(dex_register_map_bit_offset_, total_bit_size_, -1 /* min_value */);
+  }
+  ALWAYS_INLINE size_t GetEntrySize() const {
+    return RoundUp(total_bit_size_, kBitsPerByte) / kBitsPerByte;
+  }
+
+  void Dump(VariableIndentationOutputStream* vios) const;
+
+ private:
+  static constexpr uint8_t kIsLastBitOffset = 0;
+  static constexpr uint8_t kMethodIndexBitOffset = 1;
+  uint8_t dex_pc_bit_offset_;
+  uint8_t invoke_type_bit_offset_;
+  uint8_t dex_register_map_bit_offset_;
+  uint8_t total_bit_size_;
+};
+
 /**
  * Inline information for a specific PC. The information is of the form:
  *
- *   [inlining_depth, entry+]
- *
- * where `entry` is of the form:
- *
- *   [dex_pc, method_index, dex_register_map_offset].
+ *   [is_last, method_index, dex_pc, invoke_type, dex_register_map_offset]+.
  */
 class InlineInfo {
  public:
-  // Memory layout: fixed contents.
-  typedef uint8_t DepthType;
-  // Memory layout: single entry contents.
-  typedef uint32_t MethodIndexType;
-  typedef uint32_t DexPcType;
-  typedef uint8_t InvokeTypeType;
-  typedef uint32_t DexRegisterMapType;
-
-  explicit InlineInfo(MemoryRegion region) : region_(region) {}
-
-  DepthType GetDepth() const {
-    return region_.LoadUnaligned<DepthType>(kDepthOffset);
+  explicit InlineInfo(MemoryRegion region) : region_(region) {
   }
 
-  void SetDepth(DepthType depth) {
-    region_.StoreUnaligned<DepthType>(kDepthOffset, depth);
+  ALWAYS_INLINE uint32_t GetDepth(const InlineInfoEncoding& encoding) const {
+    size_t depth = 0;
+    while (!GetRegionAtDepth(encoding, depth++).LoadBit(0)) { }  // Check is_last bit.
+    return depth;
   }
 
-  MethodIndexType GetMethodIndexAtDepth(DepthType depth) const {
-    return region_.LoadUnaligned<MethodIndexType>(
-        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset);
+  ALWAYS_INLINE void SetDepth(const InlineInfoEncoding& encoding, uint32_t depth) {
+    DCHECK_GT(depth, 0u);
+    for (size_t d = 0; d < depth; ++d) {
+      GetRegionAtDepth(encoding, d).StoreBit(0, d == depth - 1);  // Set is_last bit.
+    }
   }
 
-  void SetMethodIndexAtDepth(DepthType depth, MethodIndexType index) {
-    region_.StoreUnaligned<MethodIndexType>(
-        kFixedSize + depth * SingleEntrySize() + kMethodIndexOffset, index);
+  ALWAYS_INLINE uint32_t GetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
+                                               uint32_t depth) const {
+    return encoding.GetMethodIndexEncoding().Load(GetRegionAtDepth(encoding, depth));
   }
 
-  DexPcType GetDexPcAtDepth(DepthType depth) const {
-    return region_.LoadUnaligned<DexPcType>(
-        kFixedSize + depth * SingleEntrySize() + kDexPcOffset);
+  ALWAYS_INLINE void SetMethodIndexAtDepth(const InlineInfoEncoding& encoding,
+                                           uint32_t depth,
+                                           uint32_t index) {
+    encoding.GetMethodIndexEncoding().Store(GetRegionAtDepth(encoding, depth), index);
   }
 
-  void SetDexPcAtDepth(DepthType depth, DexPcType dex_pc) {
-    region_.StoreUnaligned<DexPcType>(
-        kFixedSize + depth * SingleEntrySize() + kDexPcOffset, dex_pc);
+  ALWAYS_INLINE uint32_t GetDexPcAtDepth(const InlineInfoEncoding& encoding,
+                                         uint32_t depth) const {
+    return encoding.GetDexPcEncoding().Load(GetRegionAtDepth(encoding, depth));
   }
 
-  InvokeTypeType GetInvokeTypeAtDepth(DepthType depth) const {
-    return region_.LoadUnaligned<InvokeTypeType>(
-        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset);
+  ALWAYS_INLINE void SetDexPcAtDepth(const InlineInfoEncoding& encoding,
+                                     uint32_t depth,
+                                     uint32_t dex_pc) {
+    encoding.GetDexPcEncoding().Store(GetRegionAtDepth(encoding, depth), dex_pc);
   }
 
-  void SetInvokeTypeAtDepth(DepthType depth, InvokeTypeType invoke_type) {
-    region_.StoreUnaligned<InvokeTypeType>(
-        kFixedSize + depth * SingleEntrySize() + kInvokeTypeOffset, invoke_type);
+  ALWAYS_INLINE uint32_t GetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
+                                              uint32_t depth) const {
+    return encoding.GetInvokeTypeEncoding().Load(GetRegionAtDepth(encoding, depth));
   }
 
-  DexRegisterMapType GetDexRegisterMapOffsetAtDepth(DepthType depth) const {
-    return region_.LoadUnaligned<DexRegisterMapType>(
-        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset);
+  ALWAYS_INLINE void SetInvokeTypeAtDepth(const InlineInfoEncoding& encoding,
+                                          uint32_t depth,
+                                          uint32_t invoke_type) {
+    encoding.GetInvokeTypeEncoding().Store(GetRegionAtDepth(encoding, depth), invoke_type);
   }
 
-  void SetDexRegisterMapOffsetAtDepth(DepthType depth, DexRegisterMapType offset) {
-    region_.StoreUnaligned<DexRegisterMapType>(
-        kFixedSize + depth * SingleEntrySize() + kDexRegisterMapOffset, offset);
+  ALWAYS_INLINE uint32_t GetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
+                                                        uint32_t depth) const {
+    return encoding.GetDexRegisterMapEncoding().Load(GetRegionAtDepth(encoding, depth));
   }
 
-  bool HasDexRegisterMapAtDepth(DepthType depth) const {
-    return GetDexRegisterMapOffsetAtDepth(depth) != StackMap::kNoDexRegisterMap;
+  ALWAYS_INLINE void SetDexRegisterMapOffsetAtDepth(const InlineInfoEncoding& encoding,
+                                                    uint32_t depth,
+                                                    uint32_t offset) {
+    encoding.GetDexRegisterMapEncoding().Store(GetRegionAtDepth(encoding, depth), offset);
   }
 
-  static size_t SingleEntrySize() {
-    return kFixedEntrySize;
+  ALWAYS_INLINE bool HasDexRegisterMapAtDepth(const InlineInfoEncoding& encoding,
+                                              uint32_t depth) const {
+    return GetDexRegisterMapOffsetAtDepth(encoding, depth) != StackMap::kNoDexRegisterMap;
   }
 
   void Dump(VariableIndentationOutputStream* vios,
-            const CodeInfo& info, uint16_t* number_of_dex_registers) const;
-
+            const CodeInfo& info,
+            uint16_t* number_of_dex_registers) const;
 
  private:
-  static constexpr int kDepthOffset = 0;
-  static constexpr int kFixedSize = ELEMENT_BYTE_OFFSET_AFTER(Depth);
-
-  static constexpr int kMethodIndexOffset = 0;
-  static constexpr int kDexPcOffset = ELEMENT_BYTE_OFFSET_AFTER(MethodIndex);
-  static constexpr int kInvokeTypeOffset = ELEMENT_BYTE_OFFSET_AFTER(DexPc);
-  static constexpr int kDexRegisterMapOffset = ELEMENT_BYTE_OFFSET_AFTER(InvokeType);
-  static constexpr int kFixedEntrySize = ELEMENT_BYTE_OFFSET_AFTER(DexRegisterMap);
+  ALWAYS_INLINE MemoryRegion GetRegionAtDepth(const InlineInfoEncoding& encoding,
+                                              uint32_t depth) const {
+    size_t entry_size = encoding.GetEntrySize();
+    DCHECK_GT(entry_size, 0u);
+    return region_.Subregion(depth * entry_size, entry_size);
+  }
 
   MemoryRegion region_;
-
-  friend class CodeInfo;
-  friend class StackMap;
-  friend class StackMapStream;
 };
 
 // Most of the fields are encoded as ULEB128 to save space.
@@ -993,6 +1024,7 @@
   uint32_t stack_map_size_in_bytes;
   uint32_t number_of_location_catalog_entries;
   StackMapEncoding stack_map_encoding;
+  InlineInfoEncoding inline_info_encoding;
   uint8_t header_size;
 
   CodeInfoEncoding() { }
@@ -1003,9 +1035,18 @@
     number_of_stack_maps = DecodeUnsignedLeb128(&ptr);
     stack_map_size_in_bytes = DecodeUnsignedLeb128(&ptr);
     number_of_location_catalog_entries = DecodeUnsignedLeb128(&ptr);
-    static_assert(alignof(StackMapEncoding) == 1, "StackMapEncoding should not require alignment");
+    static_assert(alignof(StackMapEncoding) == 1,
+                  "StackMapEncoding should not require alignment");
     stack_map_encoding = *reinterpret_cast<const StackMapEncoding*>(ptr);
     ptr += sizeof(StackMapEncoding);
+    if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
+      static_assert(alignof(InlineInfoEncoding) == 1,
+                    "InlineInfoEncoding should not require alignment");
+      inline_info_encoding = *reinterpret_cast<const InlineInfoEncoding*>(ptr);
+      ptr += sizeof(InlineInfoEncoding);
+    } else {
+      inline_info_encoding = InlineInfoEncoding{}; // NOLINT.
+    }
     header_size = dchecked_integral_cast<uint8_t>(ptr - reinterpret_cast<const uint8_t*>(data));
   }
 
@@ -1015,8 +1056,12 @@
     EncodeUnsignedLeb128(dest, number_of_stack_maps);
     EncodeUnsignedLeb128(dest, stack_map_size_in_bytes);
     EncodeUnsignedLeb128(dest, number_of_location_catalog_entries);
-    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
-    dest->insert(dest->end(), ptr, ptr + sizeof(stack_map_encoding));
+    const uint8_t* stack_map_ptr = reinterpret_cast<const uint8_t*>(&stack_map_encoding);
+    dest->insert(dest->end(), stack_map_ptr, stack_map_ptr + sizeof(StackMapEncoding));
+    if (stack_map_encoding.GetInlineInfoEncoding().BitSize() > 0) {
+      const uint8_t* inline_info_ptr = reinterpret_cast<const uint8_t*>(&inline_info_encoding);
+      dest->insert(dest->end(), inline_info_ptr, inline_info_ptr + sizeof(InlineInfoEncoding));
+    }
   }
 };
 
@@ -1110,11 +1155,11 @@
                                           InlineInfo inline_info,
                                           const CodeInfoEncoding& encoding,
                                           uint32_t number_of_dex_registers) const {
-    if (!inline_info.HasDexRegisterMapAtDepth(depth)) {
+    if (!inline_info.HasDexRegisterMapAtDepth(encoding.inline_info_encoding, depth)) {
       return DexRegisterMap();
     } else {
-      uint32_t offset = GetDexRegisterMapsOffset(encoding)
-                        + inline_info.GetDexRegisterMapOffsetAtDepth(depth);
+      uint32_t offset = GetDexRegisterMapsOffset(encoding) +
+          inline_info.GetDexRegisterMapOffsetAtDepth(encoding.inline_info_encoding, depth);
       size_t size = ComputeDexRegisterMapSizeOf(encoding, offset, number_of_dex_registers);
       return DexRegisterMap(region_.Subregion(offset, size));
     }
@@ -1124,9 +1169,7 @@
     DCHECK(stack_map.HasInlineInfo(encoding.stack_map_encoding));
     uint32_t offset = stack_map.GetInlineDescriptorOffset(encoding.stack_map_encoding)
                       + GetDexRegisterMapsOffset(encoding);
-    uint8_t depth = region_.LoadUnaligned<uint8_t>(offset);
-    return InlineInfo(region_.Subregion(offset,
-        InlineInfo::kFixedSize + depth * InlineInfo::SingleEntrySize()));
+    return InlineInfo(region_.Subregion(offset, region_.size() - offset));
   }
 
   StackMap GetStackMapForDexPc(uint32_t dex_pc, const CodeInfoEncoding& encoding) const {
diff --git a/test/564-checker-bitcount/src/Main.java b/test/564-checker-bitcount/src/Main.java
index 2683b25..aad9689 100644
--- a/test/564-checker-bitcount/src/Main.java
+++ b/test/564-checker-bitcount/src/Main.java
@@ -20,67 +20,187 @@
   // CHECK-START-X86_64: int Main.bits32(int) disassembly (after)
   // CHECK-DAG: popcnt
 
-  /// CHECK-START: int Main.bits32(int) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:IntegerBitCount
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int bits32(int x) {
+
+  /// CHECK-START: int Main.$noinline$BitCountBoolean(boolean) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:IntegerBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountBoolean(boolean x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
+    return Integer.bitCount(x ? 1 : 0);
+  }
+
+  /// CHECK-START: int Main.$noinline$BitCountByte(byte) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:IntegerBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountByte(byte x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
     return Integer.bitCount(x);
   }
 
-  /// CHECK-START: int Main.bits64(long) intrinsics_recognition (after)
-  /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:LongBitCount
-  /// CHECK-DAG:                 Return [<<Result>>]
-  private static int bits64(long x) {
+  /// CHECK-START: int Main.$noinline$BitCountShort(short) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:IntegerBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountShort(short x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
+    return Integer.bitCount(x);
+  }
+
+  /// CHECK-START: int Main.$noinline$BitCountChar(char) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:IntegerBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountChar(char x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
+    return Integer.bitCount(x);
+  }
+
+  /// CHECK-START: int Main.$noinline$BitCountInt(int) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:IntegerBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountInt(int x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
+    return Integer.bitCount(x);
+  }
+
+  /// CHECK-START: int Main.$noinline$BitCountLong(long) intrinsics_recognition (after)
+  /// CHECK-DAG:     <<Result:i\d+>>  InvokeStaticOrDirect intrinsic:LongBitCount
+  /// CHECK-DAG:                      Return [<<Result>>]
+  private static int $noinline$BitCountLong(long x) {
+    if (doThrow) { throw new Error(); }  // Try defeating inlining.
     return Long.bitCount(x);
   }
 
+  public static void testBitCountBoolean() {
+    expectEqualsInt($noinline$BitCountBoolean(false), 0);
+    expectEqualsInt($noinline$BitCountBoolean(true), 1);
+  }
+
+  public static void testBitCountByte() {
+    // Number of bits in an 32-bit integer representing the sign
+    // extension of a byte value widened to an int.
+    int signExtensionSize = Integer.SIZE - Byte.SIZE;
+    // Sign bit position in a byte.
+    int signBit = Byte.SIZE - 1;
+
+    expectEqualsInt($noinline$BitCountByte((byte) 0x00), 0);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x01), 1);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x10), 1);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x11), 2);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x03), 2);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x70), 3);
+    expectEqualsInt($noinline$BitCountByte((byte) 0xF0), 4 + signExtensionSize);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x0F), 4);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x12), 2);
+    expectEqualsInt($noinline$BitCountByte((byte) 0x9A), 4 + signExtensionSize);
+    expectEqualsInt($noinline$BitCountByte((byte) 0xFF), 8 + signExtensionSize);
+
+    for (int i = 0; i < Byte.SIZE; i++) {
+      expectEqualsInt($noinline$BitCountByte((byte) (1 << i)),
+                      (i < signBit) ? 1 : 1 + signExtensionSize);
+    }
+  }
+
+  public static void testBitCountShort() {
+    // Number of bits in an 32-bit integer representing the sign
+    // extension of a short value widened to an int.
+    int signExtensionSize = Integer.SIZE - Short.SIZE;
+    // Sign bit position in a short.
+    int signBit = Short.SIZE - 1;
+
+    expectEqualsInt($noinline$BitCountShort((short) 0x0000), 0);
+    expectEqualsInt($noinline$BitCountShort((short) 0x0001), 1);
+    expectEqualsInt($noinline$BitCountShort((short) 0x1000), 1);
+    expectEqualsInt($noinline$BitCountShort((short) 0x1001), 2);
+    expectEqualsInt($noinline$BitCountShort((short) 0x0003), 2);
+    expectEqualsInt($noinline$BitCountShort((short) 0x7000), 3);
+    expectEqualsInt($noinline$BitCountShort((short) 0x0F00), 4);
+    expectEqualsInt($noinline$BitCountShort((short) 0x0011), 2);
+    expectEqualsInt($noinline$BitCountShort((short) 0x1100), 2);
+    expectEqualsInt($noinline$BitCountShort((short) 0x1111), 4);
+    expectEqualsInt($noinline$BitCountShort((short) 0x1234), 5);
+    expectEqualsInt($noinline$BitCountShort((short) 0x9ABC), 9 + signExtensionSize);
+    expectEqualsInt($noinline$BitCountShort((short) 0xFFFF), 16 + signExtensionSize);
+
+    for (int i = 0; i < Short.SIZE; i++) {
+      expectEqualsInt($noinline$BitCountShort((short) (1 << i)),
+                      (i < signBit) ? 1 : 1 + signExtensionSize);
+    }
+  }
+
+  public static void testBitCountChar() {
+    expectEqualsInt($noinline$BitCountChar((char) 0x0000), 0);
+    expectEqualsInt($noinline$BitCountChar((char) 0x0001), 1);
+    expectEqualsInt($noinline$BitCountChar((char) 0x1000), 1);
+    expectEqualsInt($noinline$BitCountChar((char) 0x1001), 2);
+    expectEqualsInt($noinline$BitCountChar((char) 0x0003), 2);
+    expectEqualsInt($noinline$BitCountChar((char) 0x7000), 3);
+    expectEqualsInt($noinline$BitCountChar((char) 0x0F00), 4);
+    expectEqualsInt($noinline$BitCountChar((char) 0x0011), 2);
+    expectEqualsInt($noinline$BitCountChar((char) 0x1100), 2);
+    expectEqualsInt($noinline$BitCountChar((char) 0x1111), 4);
+    expectEqualsInt($noinline$BitCountChar((char) 0x1234), 5);
+    expectEqualsInt($noinline$BitCountChar((char) 0x9ABC), 9);
+    expectEqualsInt($noinline$BitCountChar((char) 0xFFFF), 16);
+
+    for (int i = 0; i < Character.SIZE; i++) {
+      expectEqualsInt($noinline$BitCountChar((char) (1 << i)), 1);
+    }
+  }
+
+  public static void testBitCountInt() {
+    expectEqualsInt($noinline$BitCountInt(0x00000000), 0);
+    expectEqualsInt($noinline$BitCountInt(0x00000001), 1);
+    expectEqualsInt($noinline$BitCountInt(0x10000000), 1);
+    expectEqualsInt($noinline$BitCountInt(0x10000001), 2);
+    expectEqualsInt($noinline$BitCountInt(0x00000003), 2);
+    expectEqualsInt($noinline$BitCountInt(0x70000000), 3);
+    expectEqualsInt($noinline$BitCountInt(0x000F0000), 4);
+    expectEqualsInt($noinline$BitCountInt(0x00001111), 4);
+    expectEqualsInt($noinline$BitCountInt(0x11110000), 4);
+    expectEqualsInt($noinline$BitCountInt(0x11111111), 8);
+    expectEqualsInt($noinline$BitCountInt(0x12345678), 13);
+    expectEqualsInt($noinline$BitCountInt(0x9ABCDEF0), 19);
+    expectEqualsInt($noinline$BitCountInt(0xFFFFFFFF), 32);
+
+    for (int i = 0; i < Integer.SIZE; i++) {
+      expectEqualsInt($noinline$BitCountInt(1 << i), 1);
+    }
+  }
+
+  public static void testBitCountLong() {
+    expectEqualsInt($noinline$BitCountLong(0x0000000000000000L), 0);
+    expectEqualsInt($noinline$BitCountLong(0x0000000000000001L), 1);
+    expectEqualsInt($noinline$BitCountLong(0x1000000000000000L), 1);
+    expectEqualsInt($noinline$BitCountLong(0x1000000000000001L), 2);
+    expectEqualsInt($noinline$BitCountLong(0x0000000000000003L), 2);
+    expectEqualsInt($noinline$BitCountLong(0x7000000000000000L), 3);
+    expectEqualsInt($noinline$BitCountLong(0x000F000000000000L), 4);
+    expectEqualsInt($noinline$BitCountLong(0x0000000011111111L), 8);
+    expectEqualsInt($noinline$BitCountLong(0x1111111100000000L), 8);
+    expectEqualsInt($noinline$BitCountLong(0x1111111111111111L), 16);
+    expectEqualsInt($noinline$BitCountLong(0x123456789ABCDEF1L), 33);
+    expectEqualsInt($noinline$BitCountLong(0xFFFFFFFFFFFFFFFFL), 64);
+
+    for (int i = 0; i < Long.SIZE; i++) {
+      expectEqualsInt($noinline$BitCountLong(1L << i), 1);
+    }
+  }
+
   public static void main(String args[]) {
-    expectEquals32(bits32(0x00000000), 0);
-    expectEquals32(bits32(0x00000001), 1);
-    expectEquals32(bits32(0x10000000), 1);
-    expectEquals32(bits32(0x10000001), 2);
-    expectEquals32(bits32(0x00000003), 2);
-    expectEquals32(bits32(0x70000000), 3);
-    expectEquals32(bits32(0x000F0000), 4);
-    expectEquals32(bits32(0x00001111), 4);
-    expectEquals32(bits32(0x11110000), 4);
-    expectEquals32(bits32(0x11111111), 8);
-    expectEquals32(bits32(0x12345678), 13);
-    expectEquals32(bits32(0x9ABCDEF0), 19);
-    expectEquals32(bits32(0xFFFFFFFF), 32);
-
-    for (int i = 0; i < 32; i++) {
-      expectEquals32(bits32(1 << i), 1);
-    }
-
-    expectEquals64(bits64(0x0000000000000000L), 0);
-    expectEquals64(bits64(0x0000000000000001L), 1);
-    expectEquals64(bits64(0x1000000000000000L), 1);
-    expectEquals64(bits64(0x1000000000000001L), 2);
-    expectEquals64(bits64(0x0000000000000003L), 2);
-    expectEquals64(bits64(0x7000000000000000L), 3);
-    expectEquals64(bits64(0x000F000000000000L), 4);
-    expectEquals64(bits64(0x0000000011111111L), 8);
-    expectEquals64(bits64(0x1111111100000000L), 8);
-    expectEquals64(bits64(0x1111111111111111L), 16);
-    expectEquals64(bits64(0x123456789ABCDEF1L), 33);
-    expectEquals64(bits64(0xFFFFFFFFFFFFFFFFL), 64);
-
-    for (int i = 0; i < 64; i++) {
-      expectEquals64(bits64(1L << i), 1);
-    }
+    testBitCountBoolean();
+    testBitCountByte();
+    testBitCountShort();
+    testBitCountChar();
+    testBitCountInt();
+    testBitCountLong();
 
     System.out.println("passed");
   }
 
-  private static void expectEquals32(int expected, int result) {
+  private static void expectEqualsInt(int expected, int result) {
     if (expected != result) {
       throw new Error("Expected: " + expected + ", found: " + result);
     }
   }
-  private static void expectEquals64(long expected, long result) {
-    if (expected != result) {
-      throw new Error("Expected: " + expected + ", found: " + result);
-    }
-  }
+
+  private static boolean doThrow = false;
 }
diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py
index 6ff19d5..520c4ae 100644
--- a/tools/checker/match/file.py
+++ b/tools/checker/match/file.py
@@ -172,8 +172,8 @@
     # match a check group against the first output group of the same name.
     c1Pass = c1File.findPass(testCase.name)
     if c1Pass is None:
-      Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name),
-                  testCase.fileName, testCase.startLineNo)
+      Logger.fail("Test case not found in the CFG file",
+                  testCase.fileName, testCase.startLineNo, testCase.name)
 
     Logger.startTest(testCase.name)
     try: