Merge "De-duplicate inline info in stack maps."
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 8cd0d8b..ad94148 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -489,7 +489,7 @@
   int        sleep_ms     = 500;
   const int  sleep_max_ms = 2*1000;
 
-  android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET, 0));
+  android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
   if (sock < 0) {
     PLOG(ERROR) << "Could not create ADB control socket";
     return false;
@@ -872,7 +872,7 @@
       (ContainsArgument(opts, "server=y") ? "" : "server=y,") +
       // See the comment above for why we need to be suspend=n. Since the agent defaults to
       // suspend=y we will add it if it wasn't already present.
-      (ContainsArgument(opts, "suspend=n") ? "" : "suspend=n") +
+      (ContainsArgument(opts, "suspend=n") ? "" : "suspend=n,") +
       "transport=dt_fd_forward,address=" + std::to_string(remote_agent_control_sock_);
 }
 
diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc
index 75de238..1fe42ad 100644
--- a/compiler/dex/dex_to_dex_decompiler_test.cc
+++ b/compiler/dex/dex_to_dex_decompiler_test.cc
@@ -67,7 +67,7 @@
       class_loader = LoadDex(dex_name);
       updated_dex_file = GetDexFiles(class_loader)[0];
       Runtime::Current()->GetClassLinker()->RegisterDexFile(
-          *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader).Ptr());
+          *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader));
     }
     // The dex files should be identical.
     int cmp = memcmp(original_dex_file->Begin(),
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 028de34..dc07090 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -1342,6 +1342,14 @@
       ObjectArray<Object>::Alloc(self, object_array_class.Get(), image_roots_size)));
   image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get());
   image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots());
+  image_roots->Set<false>(ImageHeader::kOomeWhenThrowingException,
+                          runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingException());
+  image_roots->Set<false>(ImageHeader::kOomeWhenThrowingOome,
+                          runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingOOME());
+  image_roots->Set<false>(ImageHeader::kOomeWhenHandlingStackOverflow,
+                          runtime->GetPreAllocatedOutOfMemoryErrorWhenHandlingStackOverflow());
+  image_roots->Set<false>(ImageHeader::kNoClassDefFoundError,
+                          runtime->GetPreAllocatedNoClassDefFoundError());
   // image_roots[ImageHeader::kClassLoader] will be set later for app image.
   static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax,
                 "Class loader should be the last image root.");
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 4046dc1..9951668 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -4032,13 +4032,13 @@
     // TypeLookupTable allocates its own and OatDexFile takes ownership.
     const DexFile& dex_file = *opened_dex_files[i];
     {
-      std::unique_ptr<TypeLookupTable> type_lookup_table =
-          TypeLookupTable::Create(dex_file, /* storage */ nullptr);
+      TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file);
       type_lookup_table_oat_dex_files_.push_back(
           std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
       dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
     }
-    TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
+    const TypeLookupTable& table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
+    DCHECK(table.Valid());
 
     // Type tables are required to be 4 byte aligned.
     size_t initial_offset = oat_size_;
@@ -4057,9 +4057,9 @@
 
     DCHECK_EQ(oat_data_offset_ + rodata_offset,
               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
-    DCHECK_EQ(table_size, table->RawDataLength());
+    DCHECK_EQ(table_size, table.RawDataLength());
 
-    if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
+    if (!oat_rodata->WriteFully(table.RawData(), table_size)) {
       PLOG(ERROR) << "Failed to write lookup table."
                   << " File: " << oat_dex_file->GetLocation()
                   << " Output: " << oat_rodata->GetLocation();
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 0694c4f..d0a6eb9 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -545,8 +545,7 @@
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   for (const DexFile* dex_file : dex_files) {
     ScopedObjectAccess soa(Thread::Current());
-    class_linker->RegisterDexFile(*dex_file,
-                                  soa.Decode<mirror::ClassLoader>(class_loader).Ptr());
+    class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader>(class_loader));
   }
   compiler_driver_->SetDexFilesForOatFile(dex_files);
   compiler_driver_->CompileAll(class_loader, dex_files, &timings);
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 49ca98d..3bb9e93 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -37,30 +37,26 @@
       num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
       num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
 
-inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) {
-  index_ += DecodeUnsignedLeb128(&ptr);
-  access_flags_ = DecodeUnsignedLeb128(&ptr);
-  code_off_ = DecodeUnsignedLeb128(&ptr);
-  return ptr;
+inline void ClassAccessor::Method::Read() {
+  index_ += DecodeUnsignedLeb128(&ptr_pos_);
+  access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
+  code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
 }
 
-inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) {
-  index_ += DecodeUnsignedLeb128(&ptr);
-  access_flags_ = DecodeUnsignedLeb128(&ptr);
-  return ptr;
+inline void ClassAccessor::Field::Read() {
+  index_ += DecodeUnsignedLeb128(&ptr_pos_);
+  access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
 }
 
 template <typename DataType, typename Visitor>
-inline const uint8_t* ClassAccessor::VisitMembers(size_t count,
-                                                  const Visitor& visitor,
-                                                  const uint8_t* ptr,
-                                                  DataType* data) const {
+inline void ClassAccessor::VisitMembers(size_t count,
+                                        const Visitor& visitor,
+                                        DataType* data) const {
   DCHECK(data != nullptr);
   for ( ; count != 0; --count) {
-    ptr = data->Read(ptr);
+    data->Read();
     visitor(*data);
   }
-  return ptr;
 }
 
 template <typename StaticFieldVisitor,
@@ -72,15 +68,15 @@
     const InstanceFieldVisitor& instance_field_visitor,
     const DirectMethodVisitor& direct_method_visitor,
     const VirtualMethodVisitor& virtual_method_visitor) const {
-  Field field(dex_file_);
-  const uint8_t* ptr = VisitMembers(num_static_fields_, static_field_visitor, ptr_pos_, &field);
+  Field field(dex_file_, ptr_pos_);
+  VisitMembers(num_static_fields_, static_field_visitor, &field);
   field.NextSection();
-  ptr = VisitMembers(num_instance_fields_, instance_field_visitor, ptr, &field);
+  VisitMembers(num_instance_fields_, instance_field_visitor, &field);
 
-  Method method(dex_file_, /*is_static_or_direct*/ true);
-  ptr = VisitMembers(num_direct_methods_, direct_method_visitor, ptr, &method);
+  Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true);
+  VisitMembers(num_direct_methods_, direct_method_visitor, &method);
   method.NextSection();
-  ptr = VisitMembers(num_virtual_methods_, virtual_method_visitor, ptr, &method);
+  VisitMembers(num_virtual_methods_, virtual_method_visitor, &method);
 }
 
 template <typename DirectMethodVisitor,
@@ -119,23 +115,64 @@
   return dex_file_.GetCodeItem(code_off_);
 }
 
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+    ClassAccessor::GetFieldsInternal(size_t count) const {
+  return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_),
+           DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) };
+}
+
+// Return an iteration range for the first <count> methods.
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+    ClassAccessor::GetMethodsInternal(size_t count) const {
+  // Skip over the fields.
+  Field field(dex_file_, ptr_pos_);
+  VisitMembers(NumFields(), VoidFunctor(), &field);
+  // Return the iterator pair.
+  return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_),
+           DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) };
+}
+
 inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields()
     const {
-  const uint32_t limit = num_static_fields_ + num_instance_fields_;
-  return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, limit, ptr_pos_),
-           DataIterator<Field>(dex_file_, limit, num_static_fields_, limit, ptr_pos_) };
+  return GetFieldsInternal(num_static_fields_ + num_instance_fields_);
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+    ClassAccessor::GetStaticFields() const {
+  return GetFieldsInternal(num_static_fields_);
+}
+
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
+    ClassAccessor::GetInstanceFields() const {
+  IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> fields = GetFields();
+  // Skip the static fields.
+  return { std::next(fields.begin(), NumStaticFields()), fields.end() };
 }
 
 inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
     ClassAccessor::GetMethods() const {
-  // Skip over the fields.
-  Field field(dex_file_);
-  const size_t skip_count = num_static_fields_ + num_instance_fields_;
-  const uint8_t* ptr_pos = VisitMembers(skip_count, VoidFunctor(), ptr_pos_, &field);
-  // Return the iterator pair for all the methods.
-  const uint32_t limit = num_direct_methods_ + num_virtual_methods_;
-  return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, limit, ptr_pos),
-           DataIterator<Method>(dex_file_, limit, num_direct_methods_, limit, ptr_pos) };
+  return GetMethodsInternal(NumMethods());
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+    ClassAccessor::GetDirectMethods() const {
+  return GetMethodsInternal(NumDirectMethods());
+}
+
+inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
+    ClassAccessor::GetVirtualMethods() const {
+  IterationRange<DataIterator<Method>> methods = GetMethods();
+  // Skip the direct fields.
+  return { std::next(methods.begin(), NumDirectMethods()), methods.end() };
+}
+
+inline void ClassAccessor::Field::UnHideAccessFlags() const {
+  DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false);
+}
+
+inline void ClassAccessor::Method::UnHideAccessFlags() const {
+  DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true);
 }
 
 }  // namespace art
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index dda6e1c..4f0fd32 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -20,6 +20,7 @@
 #include "base/utils.h"
 #include "code_item_accessors.h"
 #include "dex_file.h"
+#include "hidden_api_access_flags.h"
 #include "invoke_type.h"
 #include "method_reference.h"
 #include "modifiers.h"
@@ -33,12 +34,18 @@
  private:
   class BaseItem {
    public:
+    explicit BaseItem(const uint8_t* ptr_pos) : ptr_pos_(ptr_pos) {}
+
     uint32_t GetIndex() const {
       return index_;
     }
 
     uint32_t GetAccessFlags() const {
-      return access_flags_;
+      return HiddenApiAccessFlags::RemoveFromDex(access_flags_);
+    }
+
+    HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const {
+      return HiddenApiAccessFlags::DecodeFromDex(access_flags_);
     }
 
     bool IsFinal() const {
@@ -46,6 +53,8 @@
     }
 
    protected:
+    // Internal data pointer for reading.
+    const uint8_t* ptr_pos_ = nullptr;
     uint32_t index_ = 0u;
     uint32_t access_flags_ = 0u;
   };
@@ -76,13 +85,18 @@
       return is_static_or_direct_;
     }
 
+    // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
+    void UnHideAccessFlags() const;
+
    private:
     explicit Method(const DexFile& dex_file,
+                    const uint8_t* ptr_pos,
                     bool is_static_or_direct = true)
-        : dex_file_(dex_file),
+        : BaseItem(ptr_pos),
+          dex_file_(dex_file),
           is_static_or_direct_(is_static_or_direct) {}
 
-    const uint8_t* Read(const uint8_t* ptr);
+    void Read();
 
     InvokeType GetDirectMethodInvokeType() const {
       return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect;
@@ -99,6 +113,7 @@
       }
     }
 
+    // Move to virtual method section.
     void NextSection() {
       DCHECK(is_static_or_direct_) << "Already in the virtual methods section";
       is_static_or_direct_ = false;
@@ -115,20 +130,31 @@
   // A decoded version of the field of a class_data_item.
   class Field : public BaseItem {
    public:
-    explicit Field(const DexFile& dex_file) : dex_file_(dex_file) {}
+    explicit Field(const DexFile& dex_file,
+                   const uint8_t* ptr_pos) : BaseItem(ptr_pos), dex_file_(dex_file) {}
 
     const DexFile& GetDexFile() const {
       return dex_file_;
     }
 
-   private:
-    const uint8_t* Read(const uint8_t* ptr);
+    bool IsStatic() const {
+     return is_static_;
+    }
 
+    // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
+    void UnHideAccessFlags() const;
+
+   private:
+    void Read();
+
+    // Move to instance fields section.
     void NextSection() {
       index_ = 0u;
+      is_static_ = false;
     }
 
     const DexFile& dex_file_;
+    bool is_static_ = true;
     friend class ClassAccessor;
   };
 
@@ -144,11 +170,10 @@
                  uint32_t partition_pos,
                  uint32_t iterator_end,
                  const uint8_t* ptr_pos)
-        : data_(dex_file),
+        : data_(dex_file, ptr_pos),
           position_(position),
           partition_pos_(partition_pos),
-          iterator_end_(iterator_end),
-          ptr_pos_(ptr_pos) {
+          iterator_end_(iterator_end) {
       ReadData();
     }
 
@@ -205,8 +230,7 @@
         if (position_ == partition_pos_) {
           data_.NextSection();
         }
-        DCHECK(ptr_pos_ != nullptr);
-        ptr_pos_ = data_.Read(ptr_pos_);
+        data_.Read();
       }
     }
 
@@ -217,8 +241,6 @@
     const uint32_t partition_pos_;
     // At iterator_end_, the iterator is no longer valid.
     const uint32_t iterator_end_;
-    // Internal data pointer.
-    const uint8_t* ptr_pos_;
   };
 
   // Not explicit specifically for range-based loops.
@@ -252,9 +274,21 @@
   // Return the iteration range for all the fields.
   IterationRange<DataIterator<Field>> GetFields() const;
 
+  // Return the iteration range for all the static fields.
+  IterationRange<DataIterator<Field>> GetStaticFields() const;
+
+  // Return the iteration range for all the instance fields.
+  IterationRange<DataIterator<Field>> GetInstanceFields() const;
+
   // Return the iteration range for all the methods.
   IterationRange<DataIterator<Method>> GetMethods() const;
 
+  // Return the iteration range for the direct methods.
+  IterationRange<DataIterator<Method>> GetDirectMethods() const;
+
+  // Return the iteration range for the virtual methods.
+  IterationRange<DataIterator<Method>> GetVirtualMethods() const;
+
   uint32_t NumStaticFields() const {
     return num_static_fields_;
   }
@@ -263,6 +297,10 @@
     return num_instance_fields_;
   }
 
+  uint32_t NumFields() const {
+    return NumStaticFields() + NumInstanceFields();
+  }
+
   uint32_t NumDirectMethods() const {
     return num_direct_methods_;
   }
@@ -285,14 +323,22 @@
     return dex_file_;
   }
 
+  bool HasClassData() const {
+    return ptr_pos_ != nullptr;
+  }
+
  protected:
   // Template visitor to reduce copy paste for visiting elements.
   // No thread safety analysis since the visitor may require capabilities.
   template <typename DataType, typename Visitor>
-  const uint8_t* VisitMembers(size_t count,
-                              const Visitor& visitor,
-                              const uint8_t* ptr,
-                              DataType* data) const NO_THREAD_SAFETY_ANALYSIS;
+  void VisitMembers(size_t count, const Visitor& visitor, DataType* data) const
+      NO_THREAD_SAFETY_ANALYSIS;
+
+  // Return an iteration range for the first <count> fields.
+  IterationRange<DataIterator<Field>> GetFieldsInternal(size_t count) const;
+
+  // Return an iteration range for the first <count> methods.
+  IterationRange<DataIterator<Method>> GetMethodsInternal(size_t count) const;
 
   const DexFile& dex_file_;
   const dex::TypeIndex descriptor_index_ = {};
diff --git a/libdexfile/dex/class_accessor_test.cc b/libdexfile/dex/class_accessor_test.cc
index 95380d8..d0533c1 100644
--- a/libdexfile/dex/class_accessor_test.cc
+++ b/libdexfile/dex/class_accessor_test.cc
@@ -38,18 +38,27 @@
       auto fields = accessor.GetFields();
       auto method_it = methods.begin();
       auto field_it = fields.begin();
+      auto instance_fields = accessor.GetInstanceFields();
+      auto instance_field_it = instance_fields.begin();
       accessor.VisitFieldsAndMethods(
           // Static fields.
           [&](const ClassAccessor::Field& field) {
+            EXPECT_TRUE(field.IsStatic());
+            EXPECT_TRUE(field_it->IsStatic());
             EXPECT_EQ(field.GetIndex(), field_it->GetIndex());
             EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags());
             ++field_it;
           },
           // Instance fields.
           [&](const ClassAccessor::Field& field) {
+            EXPECT_FALSE(field.IsStatic());
+            EXPECT_FALSE(field_it->IsStatic());
             EXPECT_EQ(field.GetIndex(), field_it->GetIndex());
             EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags());
+            EXPECT_EQ(field.GetIndex(), instance_field_it->GetIndex());
+            EXPECT_EQ(field.GetAccessFlags(), instance_field_it->GetAccessFlags());
             ++field_it;
+            ++instance_field_it;
           },
           // Direct methods.
           [&](const ClassAccessor::Method& method) {
@@ -71,6 +80,7 @@
           });
       ASSERT_TRUE(field_it == fields.end());
       ASSERT_TRUE(method_it == methods.end());
+      ASSERT_TRUE(instance_field_it == instance_fields.end());
     }
     EXPECT_EQ(class_def_idx, dex_file->NumClassDefs());
   }
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 9de260c..f570158 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -45,19 +45,18 @@
 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
 static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
 
-void DexFile::UnHideAccessFlags(ClassDataItemIterator& class_it) {
-  uint8_t* data = const_cast<uint8_t*>(class_it.DataPointer());
-  uint32_t new_flag = class_it.GetMemberAccessFlags();
-  bool is_method = class_it.IsAtMethod();
+void DexFile::UnHideAccessFlags(uint8_t* data_ptr,
+                                uint32_t new_access_flags,
+                                bool is_method) {
   // Go back 1 uleb to start.
-  data = ReverseSearchUnsignedLeb128(data);
+  data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
   if (is_method) {
     // Methods have another uleb field before the access flags
-    data = ReverseSearchUnsignedLeb128(data);
+    data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
   }
-  DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)),
-            new_flag);
-  UpdateUnsignedLeb128(data, new_flag);
+  DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)),
+            new_access_flags);
+  UpdateUnsignedLeb128(data_ptr, new_access_flags);
 }
 
 uint32_t DexFile::CalculateChecksum() const {
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index f1f8b50..ed21980 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -1010,8 +1010,8 @@
     return container_.get();
   }
 
-  // Changes the dex file pointed to by class_it to not have any hiddenapi flags.
-  static void UnHideAccessFlags(ClassDataItemIterator& class_it);
+  // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags.
+  static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method);
 
   inline IterationRange<ClassIterator> GetClasses() const;
 
diff --git a/libdexfile/dex/type_lookup_table.cc b/libdexfile/dex/type_lookup_table.cc
index ca5ec2f..00ec358 100644
--- a/libdexfile/dex/type_lookup_table.cc
+++ b/libdexfile/dex/type_lookup_table.cc
@@ -20,72 +20,43 @@
 #include <memory>
 
 #include "base/bit_utils.h"
+#include "base/leb128.h"
 #include "dex/dex_file-inl.h"
 #include "dex/utf-inl.h"
 
 namespace art {
 
-static uint16_t MakeData(uint16_t class_def_idx, uint32_t hash, uint32_t mask) {
-  uint16_t hash_mask = static_cast<uint16_t>(~mask);
-  return (static_cast<uint16_t>(hash) & hash_mask) | class_def_idx;
+static inline bool ModifiedUtf8StringEquals(const char* lhs, const char* rhs) {
+  return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(lhs, rhs) == 0;
 }
 
-TypeLookupTable::~TypeLookupTable() {
-  if (!owns_entries_) {
-    // We don't actually own the entries, don't let the unique_ptr release them.
-    entries_.release();
+TypeLookupTable TypeLookupTable::Create(const DexFile& dex_file) {
+  uint32_t num_class_defs = dex_file.NumClassDefs();
+  if (UNLIKELY(!SupportedSize(num_class_defs))) {
+    return TypeLookupTable();
   }
-}
+  size_t mask_bits = CalculateMaskBits(num_class_defs);
+  size_t size = 1u << mask_bits;
+  std::unique_ptr<Entry[]> owned_entries(new Entry[size]);
+  Entry* entries = owned_entries.get();
 
-uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) {
-  return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u;
-}
-
-uint32_t TypeLookupTable::CalculateMask(uint32_t num_class_defs) {
-  return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) - 1u : 0u;
-}
-
-bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) {
-  return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
-}
-
-std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file,
-                                                         uint8_t* storage) {
-  const uint32_t num_class_defs = dex_file.NumClassDefs();
-  return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs)
-      ? new TypeLookupTable(dex_file, storage)
-      : nullptr);
-}
-
-std::unique_ptr<TypeLookupTable> TypeLookupTable::Open(const uint8_t* dex_file_pointer,
-                                                       const uint8_t* raw_data,
-                                                       uint32_t num_class_defs) {
-  return std::unique_ptr<TypeLookupTable>(
-      new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs));
-}
-
-TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
-    : dex_data_begin_(dex_file.DataBegin()),
-      raw_data_length_(RawDataLength(dex_file.NumClassDefs())),
-      mask_(CalculateMask(dex_file.NumClassDefs())),
-      entries_(storage != nullptr ? reinterpret_cast<Entry*>(storage) : new Entry[mask_ + 1]),
-      owns_entries_(storage == nullptr) {
   static_assert(alignof(Entry) == 4u, "Expecting Entry to be 4-byte aligned.");
-  DCHECK_ALIGNED(storage, alignof(Entry));
+  const uint32_t mask = Entry::GetMask(mask_bits);
   std::vector<uint16_t> conflict_class_defs;
   // The first stage. Put elements on their initial positions. If an initial position is already
   // occupied then delay the insertion of the element to the second stage to reduce probing
   // distance.
-  for (size_t i = 0; i < dex_file.NumClassDefs(); ++i) {
-    const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
+  for (size_t class_def_idx = 0; class_def_idx < dex_file.NumClassDefs(); ++class_def_idx) {
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
     const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_);
     const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_);
     const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id));
-    Entry entry;
-    entry.str_offset = str_id.string_data_off_;
-    entry.data = MakeData(i, hash, GetSizeMask());
-    if (!SetOnInitialPos(entry, hash)) {
-      conflict_class_defs.push_back(i);
+    const uint32_t pos = hash & mask;
+    if (entries[pos].IsEmpty()) {
+      entries[pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits);
+      DCHECK(entries[pos].IsLast(mask_bits));
+    } else {
+      conflict_class_defs.push_back(class_def_idx);
     }
   }
   // The second stage. The initial position of these elements had a collision. Put these elements
@@ -95,51 +66,111 @@
     const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_);
     const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_);
     const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id));
-    Entry entry;
-    entry.str_offset = str_id.string_data_off_;
-    entry.data = MakeData(class_def_idx, hash, GetSizeMask());
-    Insert(entry, hash);
+    // Find the last entry in the chain.
+    uint32_t tail_pos = hash & mask;
+    DCHECK(!entries[tail_pos].IsEmpty());
+    while (!entries[tail_pos].IsLast(mask_bits)) {
+      tail_pos = (tail_pos + entries[tail_pos].GetNextPosDelta(mask_bits)) & mask;
+      DCHECK(!entries[tail_pos].IsEmpty());
+    }
+    // Find an empty entry for insertion.
+    uint32_t insert_pos = tail_pos;
+    do {
+      insert_pos = (insert_pos + 1) & mask;
+    } while (!entries[insert_pos].IsEmpty());
+    // Insert and chain the new entry.
+    entries[insert_pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits);
+    entries[tail_pos].SetNextPosDelta((insert_pos - tail_pos) & mask, mask_bits);
+    DCHECK(entries[insert_pos].IsLast(mask_bits));
+    DCHECK(!entries[tail_pos].IsLast(mask_bits));
   }
+
+  return TypeLookupTable(dex_file.DataBegin(), mask_bits, entries, std::move(owned_entries));
 }
 
-TypeLookupTable::TypeLookupTable(const uint8_t* dex_file_pointer,
-                                 const uint8_t* raw_data,
-                                 uint32_t num_class_defs)
-    : dex_data_begin_(dex_file_pointer),
-      raw_data_length_(RawDataLength(num_class_defs)),
-      mask_(CalculateMask(num_class_defs)),
-      entries_(reinterpret_cast<Entry*>(const_cast<uint8_t*>(raw_data))),
-      owns_entries_(false) {}
-
-bool TypeLookupTable::SetOnInitialPos(const Entry& entry, uint32_t hash) {
-  const uint32_t pos = hash & GetSizeMask();
-  if (!entries_[pos].IsEmpty()) {
-    return false;
-  }
-  entries_[pos] = entry;
-  entries_[pos].next_pos_delta = 0;
-  return true;
+TypeLookupTable TypeLookupTable::Open(const uint8_t* dex_data_pointer,
+                                      const uint8_t* raw_data,
+                                      uint32_t num_class_defs) {
+  DCHECK_ALIGNED(raw_data, alignof(Entry));
+  const Entry* entries = reinterpret_cast<const Entry*>(raw_data);
+  size_t mask_bits = CalculateMaskBits(num_class_defs);
+  return TypeLookupTable(dex_data_pointer, mask_bits, entries, /* owned_entries */ nullptr);
 }
 
-void TypeLookupTable::Insert(const Entry& entry, uint32_t hash) {
-  uint32_t pos = FindLastEntryInBucket(hash & GetSizeMask());
-  uint32_t next_pos = (pos + 1) & GetSizeMask();
-  while (!entries_[next_pos].IsEmpty()) {
-    next_pos = (next_pos + 1) & GetSizeMask();
-  }
-  const uint32_t delta = (next_pos >= pos) ? (next_pos - pos) : (next_pos + Size() - pos);
-  entries_[pos].next_pos_delta = delta;
-  entries_[next_pos] = entry;
-  entries_[next_pos].next_pos_delta = 0;
-}
-
-uint32_t TypeLookupTable::FindLastEntryInBucket(uint32_t pos) const {
+uint32_t TypeLookupTable::Lookup(const char* str, uint32_t hash) const {
+  uint32_t mask = Entry::GetMask(mask_bits_);
+  uint32_t pos = hash & mask;
+  // Thanks to special insertion algorithm, the element at position pos can be empty
+  // or start of the right bucket, or anywhere in the wrong bucket's chain.
   const Entry* entry = &entries_[pos];
-  while (!entry->IsLast()) {
-    pos = (pos + entry->next_pos_delta) & GetSizeMask();
-    entry = &entries_[pos];
+  if (entry->IsEmpty()) {
+    return dex::kDexNoIndex;
   }
-  return pos;
+  // Look for the partial hash match first, even if traversing the wrong bucket's chain.
+  uint32_t compared_hash_bits = (hash << mask_bits_) >> (2 * mask_bits_);
+  while (compared_hash_bits != entry->GetHashBits(mask_bits_)) {
+    if (entry->IsLast(mask_bits_)) {
+      return dex::kDexNoIndex;
+    }
+    pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask;
+    entry = &entries_[pos];
+    DCHECK(!entry->IsEmpty());
+  }
+  // Found partial hash match, compare strings (expecting this to succeed).
+  const char* first_checked_str = GetStringData(*entry);
+  if (ModifiedUtf8StringEquals(str, first_checked_str)) {
+    return entry->GetClassDefIdx(mask_bits_);
+  }
+  // If we're at the end of the chain, return before doing further expensive work.
+  if (entry->IsLast(mask_bits_)) {
+    return dex::kDexNoIndex;
+  }
+  // Check if we're traversing the right bucket. This is important if the compared
+  // partial hash has only a few bits (i.e. it can match frequently).
+  if (((ComputeModifiedUtf8Hash(first_checked_str) ^ hash) & mask) != 0u) {
+    return dex::kDexNoIndex;  // Low hash bits mismatch.
+  }
+  // Continue looking for the string in the rest of the chain.
+  do {
+    pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask;
+    entry = &entries_[pos];
+    DCHECK(!entry->IsEmpty());
+    if (compared_hash_bits == entry->GetHashBits(mask_bits_) &&
+        ModifiedUtf8StringEquals(str, GetStringData(*entry))) {
+      return entry->GetClassDefIdx(mask_bits_);
+    }
+  } while (!entry->IsLast(mask_bits_));
+  // Not found.
+  return dex::kDexNoIndex;
+}
+
+uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) {
+  return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u;
+}
+
+uint32_t TypeLookupTable::CalculateMaskBits(uint32_t num_class_defs) {
+  return SupportedSize(num_class_defs) ? MinimumBitsToStore(num_class_defs - 1u) : 0u;
+}
+
+bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) {
+  return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
+}
+
+TypeLookupTable::TypeLookupTable(const uint8_t* dex_data_pointer,
+                                 uint32_t mask_bits,
+                                 const Entry* entries,
+                                 std::unique_ptr<Entry[]> owned_entries)
+    : dex_data_begin_(dex_data_pointer),
+      mask_bits_(mask_bits),
+      entries_(entries),
+      owned_entries_(std::move(owned_entries)) {}
+
+const char* TypeLookupTable::GetStringData(const Entry& entry) const {
+  DCHECK(dex_data_begin_ != nullptr);
+  const uint8_t* ptr = dex_data_begin_ + entry.GetStringOffset();
+  // Skip string length.
+  DecodeUnsignedLeb128(&ptr);
+  return reinterpret_cast<const char*>(ptr);
 }
 
 }  // namespace art
diff --git a/libdexfile/dex/type_lookup_table.h b/libdexfile/dex/type_lookup_table.h
index 0ba2b75..7005d34 100644
--- a/libdexfile/dex/type_lookup_table.h
+++ b/libdexfile/dex/type_lookup_table.h
@@ -17,9 +17,8 @@
 #ifndef ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
 #define ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
 
-#include "base/leb128.h"
+#include "base/logging.h"
 #include "dex/dex_file_types.h"
-#include "dex/utf.h"
 
 namespace art {
 
@@ -34,140 +33,146 @@
  */
 class TypeLookupTable {
  public:
-  ~TypeLookupTable();
+  // Method creates lookup table for dex file.
+  static TypeLookupTable Create(const DexFile& dex_file);
+
+  // Method opens lookup table from binary data. Lookups will traverse strings and other
+  // data contained in dex_file as well.  Lookup table does not own raw_data or dex_file.
+  static TypeLookupTable Open(const uint8_t* dex_data_pointer,
+                              const uint8_t* raw_data,
+                              uint32_t num_class_defs);
+
+  // Create an invalid lookup table.
+  TypeLookupTable()
+      : dex_data_begin_(nullptr),
+        mask_bits_(0u),
+        entries_(nullptr),
+        owned_entries_(nullptr) {}
+
+  TypeLookupTable(TypeLookupTable&& src) noexcept = default;
+  TypeLookupTable& operator=(TypeLookupTable&& src) noexcept = default;
+
+  ~TypeLookupTable() {
+    // Implicit deallocation by std::unique_ptr<> destructor.
+  }
+
+  // Returns whether the TypeLookupTable is valid.
+  bool Valid() const {
+    return entries_ != nullptr;
+  }
 
   // Return the number of buckets in the lookup table.
   uint32_t Size() const {
-    return mask_ + 1;
+    DCHECK(Valid());
+    return 1u << mask_bits_;
   }
 
   // Method search class_def_idx by class descriptor and it's hash.
   // If no data found then the method returns dex::kDexNoIndex.
-  uint32_t Lookup(const char* str, uint32_t hash) const {
-    uint32_t pos = hash & GetSizeMask();
-    // Thanks to special insertion algorithm, the element at position pos can be empty or start of
-    // bucket.
-    const Entry* entry = &entries_[pos];
-    while (!entry->IsEmpty()) {
-      if (CmpHashBits(entry->data, hash) && IsStringsEquals(str, entry->str_offset)) {
-        return GetClassDefIdx(entry->data);
-      }
-      if (entry->IsLast()) {
-        return dex::kDexNoIndex;
-      }
-      pos = (pos + entry->next_pos_delta) & GetSizeMask();
-      entry = &entries_[pos];
-    }
-    return dex::kDexNoIndex;
-  }
-
-  // Method creates lookup table for dex file
-  static std::unique_ptr<TypeLookupTable> Create(const DexFile& dex_file,
-                                                 uint8_t* storage = nullptr);
-
-  // Method opens lookup table from binary data. Lookups will traverse strings and other
-  // data contained in dex_file as well.  Lookup table does not own raw_data or dex_file.
-  static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer,
-                                               const uint8_t* raw_data,
-                                               uint32_t num_class_defs);
+  uint32_t Lookup(const char* str, uint32_t hash) const;
 
   // Method returns pointer to binary data of lookup table. Used by the oat writer.
   const uint8_t* RawData() const {
-    return reinterpret_cast<const uint8_t*>(entries_.get());
+    DCHECK(Valid());
+    return reinterpret_cast<const uint8_t*>(entries_);
   }
 
   // Method returns length of binary data. Used by the oat writer.
-  uint32_t RawDataLength() const { return raw_data_length_; }
+  uint32_t RawDataLength() const {
+    DCHECK(Valid());
+    return Size() * sizeof(Entry);
+  }
 
   // Method returns length of binary data for the specified number of class definitions.
   static uint32_t RawDataLength(uint32_t num_class_defs);
 
  private:
-   /**
-    * To find element we need to compare strings.
-    * It is faster to compare first hashes and then strings itself.
-    * But we have no full hash of element of table. But we can use 2 ideas.
-    * 1. All minor bits of hash inside one bucket are equals.
-    * 2. If dex file contains N classes and size of hash table is 2^n (where N <= 2^n)
-    *    then 16-n bits are free. So we can encode part of element's hash into these bits.
-    * So hash of element can be divided on three parts:
-    * XXXX XXXX XXXX YYYY YZZZ ZZZZ ZZZZZ
-    * Z - a part of hash encoded in bucket (these bits of has are same for all elements in bucket) -
-    * n bits
-    * Y - a part of hash that we can write into free 16-n bits (because only n bits used to store
-    * class_def_idx)
-    * X - a part of has that we can't use without increasing increase
-    * So the data element of Entry used to store class_def_idx and part of hash of the entry.
-    */
-  struct Entry {
-    uint32_t str_offset;
-    uint16_t data;
-    uint16_t next_pos_delta;
+  /**
+   * To find element we need to compare strings.
+   * It is faster to compare first hashes and then strings itself.
+   * But we have no full hash of element of table. But we can use 2 ideas.
+   * 1. All minor bits of hash inside one bucket are equal.
+   *    (TODO: We're not actually using this, are we?)
+   * 2. If the dex file contains N classes and the size of the hash table is 2^n (where N <= 2^n)
+   *    then we need n bits for the class def index and n bits for the next position delta.
+   *    So we can encode part of element's hash into the remaining 32-2*n (n <= 16) bits which
+   *    would be otherwise wasted as a padding.
+   * So hash of element can be divided on three parts:
+   *     XXXX XXXX XXXY YYYY YYYY YZZZ ZZZZ ZZZZ  (example with n=11)
+   *     Z - a part of hash encoded implicitly in the bucket index
+   *         (these bits are same for all elements in bucket)
+   *     Y - a part of hash that we can write into free 32-2*n bits
+   *     X - a part of hash that we can't use without increasing the size of the entry
+   * So the `data` element of Entry is used to store the next position delta, class_def_index
+   * and a part of hash of the entry.
+   */
+  class Entry {
+   public:
+    Entry() : str_offset_(0u), data_(0u) {}
+    Entry(uint32_t str_offset, uint32_t hash, uint32_t class_def_index, uint32_t mask_bits)
+        : str_offset_(str_offset),
+          data_(((hash & ~GetMask(mask_bits)) | class_def_index) << mask_bits) {
+      DCHECK_EQ(class_def_index & ~GetMask(mask_bits), 0u);
+    }
 
-    Entry() : str_offset(0), data(0), next_pos_delta(0) {}
+    void SetNextPosDelta(uint32_t next_pos_delta, uint32_t mask_bits) {
+      DCHECK_EQ(GetNextPosDelta(mask_bits), 0u);
+      DCHECK_EQ(next_pos_delta & ~GetMask(mask_bits), 0u);
+      DCHECK_NE(next_pos_delta, 0u);
+      data_ |= next_pos_delta;
+    }
 
     bool IsEmpty() const {
-      return str_offset == 0;
+      return str_offset_ == 0u;
     }
 
-    bool IsLast() const {
-      return next_pos_delta == 0;
+    bool IsLast(uint32_t mask_bits) const {
+      return GetNextPosDelta(mask_bits) == 0u;
     }
+
+    uint32_t GetStringOffset() const {
+      return str_offset_;
+    }
+
+    uint32_t GetNextPosDelta(uint32_t mask_bits) const {
+      return data_ & GetMask(mask_bits);
+    }
+
+    uint32_t GetClassDefIdx(uint32_t mask_bits) const {
+      return (data_ >> mask_bits) & GetMask(mask_bits);
+    }
+
+    uint32_t GetHashBits(uint32_t mask_bits) const {
+      DCHECK_LE(mask_bits, 16u);
+      return data_ >> (2u * mask_bits);
+    }
+
+    static uint32_t GetMask(uint32_t mask_bits) {
+      DCHECK_LE(mask_bits, 16u);
+      return ~(std::numeric_limits<uint32_t>::max() << mask_bits);
+    }
+
+   private:
+    uint32_t str_offset_;
+    uint32_t data_;
   };
 
-  static uint32_t CalculateMask(uint32_t num_class_defs);
+  static uint32_t CalculateMaskBits(uint32_t num_class_defs);
   static bool SupportedSize(uint32_t num_class_defs);
 
-  // Construct from a dex file.
-  explicit TypeLookupTable(const DexFile& dex_file, uint8_t* storage);
+  // Construct the TypeLookupTable.
+  TypeLookupTable(const uint8_t* dex_data_pointer,
+                  uint32_t mask_bits,
+                  const Entry* entries,
+                  std::unique_ptr<Entry[]> owned_entries);
 
-  // Construct from a dex file with existing data.
-  TypeLookupTable(const uint8_t* dex_file_pointer,
-                  const uint8_t* raw_data,
-                  uint32_t num_class_defs);
-
-  bool IsStringsEquals(const char* str, uint32_t str_offset) const {
-    const uint8_t* ptr = dex_data_begin_ + str_offset;
-    CHECK(dex_data_begin_ != nullptr);
-    // Skip string length.
-    DecodeUnsignedLeb128(&ptr);
-    return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(
-        str, reinterpret_cast<const char*>(ptr)) == 0;
-  }
-
-  // Method extracts hash bits from element's data and compare them with
-  // the corresponding bits of the specified hash
-  bool CmpHashBits(uint32_t data, uint32_t hash) const {
-    uint32_t mask = static_cast<uint16_t>(~GetSizeMask());
-    return (hash & mask) == (data & mask);
-  }
-
-  uint32_t GetClassDefIdx(uint32_t data) const {
-    return data & mask_;
-  }
-
-  uint32_t GetSizeMask() const {
-    return mask_;
-  }
-
-  // Attempt to set an entry on its hash's slot. If there is already something there, return false.
-  // Otherwise return true.
-  bool SetOnInitialPos(const Entry& entry, uint32_t hash);
-
-  // Insert an entry, probes until there is an empty slot.
-  void Insert(const Entry& entry, uint32_t hash);
-
-  // Find the last entry in a chain.
-  uint32_t FindLastEntryInBucket(uint32_t cur_pos) const;
+  const char* GetStringData(const Entry& entry) const;
 
   const uint8_t* dex_data_begin_;
-  const uint32_t raw_data_length_;
-  const uint32_t mask_;
-  std::unique_ptr<Entry[]> entries_;
-  // owns_entries_ specifies if the lookup table owns the entries_ array.
-  const bool owns_entries_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(TypeLookupTable);
+  uint32_t mask_bits_;
+  const Entry* entries_;
+  // `owned_entries_` is either null (not owning `entries_`) or same pointer as `entries_`.
+  std::unique_ptr<Entry[]> owned_entries_;
 };
 
 }  // namespace art
diff --git a/libdexfile/dex/type_lookup_table_test.cc b/libdexfile/dex/type_lookup_table_test.cc
index 6c3d291..4316be0 100644
--- a/libdexfile/dex/type_lookup_table_test.cc
+++ b/libdexfile/dex/type_lookup_table_test.cc
@@ -30,20 +30,20 @@
 
 TEST_F(TypeLookupTableTest, CreateLookupTable) {
   std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
-  std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
-  ASSERT_NE(nullptr, table.get());
-  ASSERT_NE(nullptr, table->RawData());
-  ASSERT_EQ(32U, table->RawDataLength());
+  TypeLookupTable table = TypeLookupTable::Create(*dex_file);
+  ASSERT_TRUE(table.Valid());
+  ASSERT_NE(nullptr, table.RawData());
+  ASSERT_EQ(32U, table.RawDataLength());
 }
 
 TEST_P(TypeLookupTableTest, Find) {
   std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup"));
-  std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file));
-  ASSERT_NE(nullptr, table.get());
+  TypeLookupTable table(TypeLookupTable::Create(*dex_file));
+  ASSERT_TRUE(table.Valid());
   auto pair = GetParam();
   const char* descriptor = pair.first;
   size_t hash = ComputeModifiedUtf8Hash(descriptor);
-  uint32_t class_def_idx = table->Lookup(descriptor, hash);
+  uint32_t class_def_idx = table.Lookup(descriptor, hash);
   ASSERT_EQ(pair.second, class_def_idx);
 }
 
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 7ac9e98..7b72e18 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -105,6 +105,10 @@
 const char* image_roots_descriptions_[] = {
   "kDexCaches",
   "kClassRoots",
+  "kOomeWhenThrowingException",
+  "kOomeWhenThrowingOome",
+  "kOomeWhenHandlingStackOverflow",
+  "kNoClassDefFoundError",
   "kClassLoader",
 };
 
@@ -1942,17 +1946,17 @@
     os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n";
 
     {
-      os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n";
+      os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots().Ptr()) << "\n";
       static_assert(arraysize(image_roots_descriptions_) ==
           static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match");
       DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax);
       for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) {
         ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
         const char* image_root_description = image_roots_descriptions_[i];
-        mirror::Object* image_root_object = image_header_.GetImageRoot(image_root);
-        indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object);
+        ObjPtr<mirror::Object> image_root_object = image_header_.GetImageRoot(image_root);
+        indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object.Ptr());
         if (image_root_object != nullptr && image_root_object->IsObjectArray()) {
-          mirror::ObjectArray<mirror::Object>* image_root_object_array
+          ObjPtr<mirror::ObjectArray<mirror::Object>> image_root_object_array
               = image_root_object->AsObjectArray<mirror::Object>();
           ScopedIndentation indent2(&vios_);
           for (int j = 0; j < image_root_object_array->GetLength(); j++) {
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index be1ab78..765225a 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -401,7 +401,7 @@
     art::ThrowNullPointerException("object == null");
     return JNI_FALSE;
   }
-  return soa.Self()->HoldsLock(object.Ptr());
+  return soa.Self()->HoldsLock(object);
 }
 
 JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) {
diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc
index fcbafe7..a660fb5 100644
--- a/openjdkjvmti/fixed_up_dex_file.cc
+++ b/openjdkjvmti/fixed_up_dex_file.cc
@@ -31,6 +31,7 @@
 
 #include "base/leb128.h"
 #include "fixed_up_dex_file.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
 #include "dex/dex_file_verifier.h"
@@ -51,14 +52,12 @@
 }
 
 static void UnhideApis(const art::DexFile& target_dex_file) {
-  for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
-    const uint8_t* class_data = target_dex_file.GetClassData(target_dex_file.GetClassDef(i));
-    if (class_data != nullptr) {
-      for (art::ClassDataItemIterator class_it(target_dex_file, class_data);
-           class_it.HasNext();
-           class_it.Next()) {
-        art::DexFile::UnHideAccessFlags(class_it);
-      }
+  for (art::ClassAccessor accessor : target_dex_file.GetClasses()) {
+    for (const art::ClassAccessor::Field& field : accessor.GetFields()) {
+      field.UnHideAccessFlags();
+    }
+    for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+      method.UnHideAccessFlags();
     }
   }
 }
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 73e3719..50d8dfe 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -526,7 +526,7 @@
     return art::mirror::ByteArray::AllocateAndFill(
         driver_->self_,
         reinterpret_cast<const signed char*>(original_dex_file_.data()),
-        original_dex_file_.size());
+        original_dex_file_.size()).Ptr();
   }
 
   // See if we already have one set.
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index a6d3903..3c0b3e4 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -973,7 +973,7 @@
   ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   CHECK_GT(image_->Size(), sizeof(ImageHeader));
   // These are the roots from the original file.
-  auto* img_roots = image_header->GetImageRoots();
+  mirror::ObjectArray<mirror::Object>* img_roots = image_header->GetImageRoots().Ptr();
   image_header->RelocateImage(delta_);
 
   PatchArtFields(image_header);
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index baa5102..c5fb7d5 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -21,7 +21,7 @@
 
 #include <android-base/logging.h>
 
-#include "class_linker.h"
+#include "class_linker-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/primitive.h"
 #include "gc/accounting/card_table-inl.h"
@@ -339,16 +339,11 @@
   return GetDexCache<kWithoutReadBarrier>()->GetDexFile();
 }
 
-inline ObjPtr<mirror::String> ArtField::GetStringName(Thread* self, bool resolve) {
-  auto dex_field_index = GetDexFieldIndex();
+inline ObjPtr<mirror::String> ArtField::ResolveNameString() {
+  uint32_t dex_field_index = GetDexFieldIndex();
   CHECK_NE(dex_field_index, dex::kDexNoIndex);
-  ObjPtr<mirror::DexCache> dex_cache = GetDexCache();
-  const DexFile::FieldId& field_id = dex_cache->GetDexFile()->GetFieldId(dex_field_index);
-  ObjPtr<mirror::String> name = dex_cache->GetResolvedString(field_id.name_idx_);
-  if (resolve && name == nullptr) {
-    name = ResolveGetStringName(self, field_id.name_idx_, dex_cache);
-  }
-  return name;
+  const DexFile::FieldId& field_id = GetDexFile()->GetFieldId(dex_field_index);
+  return Runtime::Current()->GetClassLinker()->ResolveString(field_id.name_idx_, this);
 }
 
 template <typename Visitor>
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index b867621..6cbd9e4 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -52,13 +52,6 @@
   return klass;
 }
 
-ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self,
-                                                      dex::StringIndex string_idx,
-                                                      ObjPtr<mirror::DexCache> dex_cache) {
-  StackHandleScope<1> hs(self);
-  return Runtime::Current()->GetClassLinker()->ResolveString(string_idx, hs.NewHandle(dex_cache));
-}
-
 std::string ArtField::PrettyField(ArtField* f, bool with_type) {
   if (f == nullptr) {
     return "null";
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 784a862..123595c 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -201,8 +201,7 @@
   const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolves / returns the name from the dex cache.
-  ObjPtr<mirror::String> GetStringName(Thread* self, bool resolve)
-      REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_);
 
   const char* GetTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -241,10 +240,6 @@
 
   ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
-                                              dex::StringIndex string_idx,
-                                              ObjPtr<mirror::DexCache> dex_cache)
-      REQUIRES_SHARED(Locks::mutator_lock_);
 
   void GetAccessFlagsDCheck() REQUIRES_SHARED(Locks::mutator_lock_);
   void GetOffsetDCheck() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index ec66966..18595cf 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -245,6 +245,12 @@
   }
 }
 
+inline ObjPtr<mirror::String> ArtMethod::ResolveNameString() {
+  DCHECK(!IsProxyMethod());
+  const DexFile::MethodId& method_id = GetDexFile()->GetMethodId(GetDexMethodIndex());
+  return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, this);
+}
+
 inline const DexFile::CodeItem* ArtMethod::GetCodeItem() {
   return GetDexFile()->GetCodeItem(GetCodeItemOffset());
 }
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 151c36f..45bf664 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -26,6 +26,7 @@
 #include "class_linker-inl.h"
 #include "class_root.h"
 #include "debugger.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_exception_helpers.h"
@@ -142,16 +143,6 @@
   return dex_file->GetIndexForClassDef(*class_def);
 }
 
-ObjPtr<mirror::String> ArtMethod::GetNameAsString(Thread* self) {
-  CHECK(!IsProxyMethod());
-  StackHandleScope<1> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache()));
-  auto* dex_file = dex_cache->GetDexFile();
-  uint32_t dex_method_idx = GetDexMethodIndex();
-  const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx);
-  return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, dex_cache);
-}
-
 void ArtMethod::ThrowInvocationTimeError() {
   DCHECK(!IsInvokable());
   // NOTE: IsDefaultConflicting must be first since the actual method might or might not be abstract
@@ -434,28 +425,14 @@
 static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file,
                                                  uint16_t class_def_idx,
                                                  uint32_t method_idx) {
-  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
-  const uint8_t* class_data = dex_file.GetClassData(class_def);
-  CHECK(class_data != nullptr);
-  ClassDataItemIterator it(dex_file, class_data);
-  it.SkipAllFields();
-  // Process methods
-  size_t class_def_method_index = 0;
-  while (it.HasNextDirectMethod()) {
-    if (it.GetMemberIndex() == method_idx) {
+  ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx));
+  uint32_t class_def_method_index = 0u;
+  for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+    if (method.GetIndex() == method_idx) {
       return class_def_method_index;
     }
     class_def_method_index++;
-    it.Next();
   }
-  while (it.HasNextVirtualMethod()) {
-    if (it.GetMemberIndex() == method_idx) {
-      return class_def_method_index;
-    }
-    class_def_method_index++;
-    it.Next();
-  }
-  DCHECK(!it.HasNext());
   LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation();
   UNREACHABLE();
 }
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 012d706..09debb0 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -589,7 +589,7 @@
 
   ALWAYS_INLINE const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ObjPtr<mirror::String> GetNameAsString(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_);
 
   const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
 
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 888f713..2536b23 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -35,20 +35,19 @@
 namespace art {
 
 inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self,
-                                                         ObjPtr<mirror::Class>* element_class) {
+                                                         ObjPtr<mirror::Class> element_class) {
   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
     // Read the cached array class once to avoid races with other threads setting it.
     ObjPtr<mirror::Class> array_class = find_array_class_cache_[i].Read();
-    if (array_class != nullptr && array_class->GetComponentType() == *element_class) {
-      return array_class.Ptr();
+    if (array_class != nullptr && array_class->GetComponentType() == element_class) {
+      return array_class;
     }
   }
   std::string descriptor = "[";
   std::string temp;
-  descriptor += (*element_class)->GetDescriptor(&temp);
-  StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle((*element_class)->GetClassLoader()));
-  HandleWrapperObjPtr<mirror::Class> h_element_class(hs.NewHandleWrapper(element_class));
+  descriptor += element_class->GetDescriptor(&temp);
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(element_class->GetClassLoader()));
   ObjPtr<mirror::Class> array_class = FindClass(self, descriptor.c_str(), class_loader);
   if (array_class != nullptr) {
     // Benign races in storing array class and incrementing index.
@@ -59,7 +58,55 @@
     // We should have a NoClassDefFoundError.
     self->AssertPendingException();
   }
-  return array_class.Ptr();
+  return array_class;
+}
+
+inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
+                                                         ArtField* referrer) {
+  Thread::PoisonObjectPointersIfDebug();
+  DCHECK(!Thread::Current()->IsExceptionPending());
+  // We do not need the read barrier for getting the DexCache for the initial resolved type
+  // lookup as both from-space and to-space copies point to the same native resolved types array.
+  ObjPtr<mirror::String> resolved =
+      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
+  if (resolved == nullptr) {
+    resolved = DoResolveString(string_idx, referrer->GetDexCache());
+  }
+  return resolved;
+}
+
+inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
+                                                         ArtMethod* referrer) {
+  Thread::PoisonObjectPointersIfDebug();
+  DCHECK(!Thread::Current()->IsExceptionPending());
+  // We do not need the read barrier for getting the DexCache for the initial resolved type
+  // lookup as both from-space and to-space copies point to the same native resolved types array.
+  ObjPtr<mirror::String> resolved =
+      referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx);
+  if (resolved == nullptr) {
+    resolved = DoResolveString(string_idx, referrer->GetDexCache());
+  }
+  return resolved;
+}
+
+inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
+                                                         Handle<mirror::DexCache> dex_cache) {
+  Thread::PoisonObjectPointersIfDebug();
+  DCHECK(!Thread::Current()->IsExceptionPending());
+  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
+  if (resolved == nullptr) {
+    resolved = DoResolveString(string_idx, dex_cache);
+  }
+  return resolved;
+}
+
+inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
+                                                        ObjPtr<mirror::DexCache> dex_cache) {
+  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
+  if (resolved == nullptr) {
+    resolved = DoLookupString(string_idx, dex_cache);
+  }
+  return resolved;
 }
 
 inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index dccdff0..6933174 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -56,6 +56,7 @@
 #include "compiler_callbacks.h"
 #include "debug_print.h"
 #include "debugger.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_exception_helpers.h"
@@ -197,8 +198,7 @@
     }
   } else {
     // Previous error has been stored as an instance. Just rethrow.
-    ObjPtr<mirror::Class> throwable_class =
-        self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass();
+    ObjPtr<mirror::Class> throwable_class = GetClassRoot<mirror::Throwable>(class_linker);
     ObjPtr<mirror::Class> error_class = obj->GetClass();
     CHECK(throwable_class->IsAssignableFrom(error_class));
     self->SetException(obj->AsThrowable());
@@ -376,7 +376,6 @@
     : boot_class_table_(new ClassTable()),
       failed_dex_cache_class_lookups_(0),
       class_roots_(nullptr),
-      array_iftable_(nullptr),
       find_array_class_cache_next_victim_(0),
       init_done_(false),
       log_new_roots_(false),
@@ -432,8 +431,8 @@
   heap->IncrementDisableMovingGC(self);
   StackHandleScope<64> hs(self);  // 64 is picked arbitrarily.
   auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_);
-  Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>(
-      heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor()))));
+  Handle<mirror::Class> java_lang_Class(hs.NewHandle(ObjPtr<mirror::Class>::DownCast(MakeObjPtr(
+      heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor())))));
   CHECK(java_lang_Class != nullptr);
   java_lang_Class->SetClassFlags(mirror::kClassFlagClass);
   java_lang_Class->SetClass(java_lang_Class.Get());
@@ -512,6 +511,10 @@
   // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set.
   java_lang_Object->SetIfTable(AllocIfTable(self, 0));
 
+  // Create array interface entries to populate once we can load system classes.
+  object_array_class->SetIfTable(AllocIfTable(self, 2));
+  DCHECK_EQ(GetArrayIfTable(), object_array_class->GetIfTable());
+
   // Setup the primitive type classes.
   SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
   SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
@@ -523,9 +526,6 @@
   SetClassRoot(ClassRoot::kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble));
   SetClassRoot(ClassRoot::kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid));
 
-  // Create array interface entries to populate once we can load system classes.
-  array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2));
-
   // Create int array type for native pointer arrays (for example vtables) on 32-bit archs.
   Handle<mirror::Class> int_array_class(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
@@ -639,8 +639,8 @@
   CHECK(java_io_Serializable != nullptr);
   // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
   // crawl up and explicitly list all of the supers as well.
-  array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get());
-  array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get());
+  object_array_class->GetIfTable()->SetInterface(0, java_lang_Cloneable.Get());
+  object_array_class->GetIfTable()->SetInterface(1, java_io_Serializable.Get());
 
   // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread
   // suspension.
@@ -841,7 +841,7 @@
     // if possible add new checks there to catch errors early
   }
 
-  CHECK(!array_iftable_.IsNull());
+  CHECK(GetArrayIfTable() != nullptr);
 
   // disable the slow paths in FindClass and CreatePrimitiveClass now
   // that Object, Class, and Object[] are setup
@@ -988,8 +988,8 @@
   }
 
   class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
-      down_cast<mirror::ObjectArray<mirror::Class>*>(
-          spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)));
+      ObjPtr<mirror::ObjectArray<mirror::Class>>::DownCast(MakeObjPtr(
+          spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))));
   DCHECK_EQ(GetClassRoot(ClassRoot::kJavaLangClass, this)->GetClassFlags(),
             mirror::kClassFlagClass);
 
@@ -1000,11 +1000,6 @@
   runtime->SetSentinel(heap->AllocNonMovableObject<true>(
       self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
 
-  // reinit array_iftable_ from any array class instance, they should be ==
-  array_iftable_ =
-      GcRoot<mirror::IfTable>(GetClassRoot(ClassRoot::kObjectArrayClass, this)->GetIfTable());
-  DCHECK_EQ(array_iftable_.Read(), GetClassRoot(ClassRoot::kBooleanArrayClass, this)->GetIfTable());
-
   for (gc::space::ImageSpace* image_space : spaces) {
     // Boot class loader, use a null handle.
     std::vector<std::unique_ptr<const DexFile>> dex_files;
@@ -1094,7 +1089,7 @@
         return false;    // Stop the visit.
       }
       if (name != nullptr) {
-        out_dex_file_names->push_front(name.Ptr());
+        out_dex_file_names->push_front(name);
       }
       return true;  // Continue with the next Element.
     };
@@ -1931,7 +1926,6 @@
 void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) {
   class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   VisitClassRoots(visitor, flags);
-  array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   // Instead of visiting the find_array_class_cache_ drop it so that it doesn't prevent class
   // unloading if we are marking roots.
   DropFindArrayClassCache();
@@ -2114,16 +2108,16 @@
   delete data.class_table;
 }
 
-mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) {
-  return down_cast<mirror::PointerArray*>(
+ObjPtr<mirror::PointerArray> ClassLinker::AllocPointerArray(Thread* self, size_t length) {
+  return ObjPtr<mirror::PointerArray>::DownCast(
       image_pointer_size_ == PointerSize::k64
-          ? static_cast<mirror::Array*>(mirror::LongArray::Alloc(self, length))
-          : static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length)));
+          ? ObjPtr<mirror::Array>(mirror::LongArray::Alloc(self, length))
+          : ObjPtr<mirror::Array>(mirror::IntArray::Alloc(self, length)));
 }
 
-mirror::DexCache* ClassLinker::AllocDexCache(ObjPtr<mirror::String>* out_location,
-                                             Thread* self,
-                                             const DexFile& dex_file) {
+ObjPtr<mirror::DexCache> ClassLinker::AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location,
+                                                    Thread* self,
+                                                    const DexFile& dex_file) {
   StackHandleScope<1> hs(self);
   DCHECK(out_location != nullptr);
   auto dex_cache(hs.NewHandle(ObjPtr<mirror::DexCache>::DownCast(
@@ -2141,9 +2135,9 @@
   return dex_cache.Get();
 }
 
-mirror::DexCache* ClassLinker::AllocAndInitializeDexCache(Thread* self,
-                                                          const DexFile& dex_file,
-                                                          LinearAlloc* linear_alloc) {
+ObjPtr<mirror::DexCache> ClassLinker::AllocAndInitializeDexCache(Thread* self,
+                                                                 const DexFile& dex_file,
+                                                                 LinearAlloc* linear_alloc) {
   ObjPtr<mirror::String> location = nullptr;
   ObjPtr<mirror::DexCache> dex_cache = AllocDexCache(&location, self, dex_file);
   if (dex_cache != nullptr) {
@@ -2156,7 +2150,7 @@
                                          linear_alloc,
                                          image_pointer_size_);
   }
-  return dex_cache.Ptr();
+  return dex_cache;
 }
 
 ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self,
@@ -2179,7 +2173,7 @@
   return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size);
 }
 
-mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray(
+ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> ClassLinker::AllocStackTraceElementArray(
     Thread* self,
     size_t length) {
   return mirror::ObjectArray<mirror::StackTraceElement>::Alloc(
@@ -2260,7 +2254,7 @@
   // Return the loaded class.  No exceptions should be pending.
   CHECK(klass->IsResolved()) << klass->PrettyClass();
   self->AssertNoPendingException();
-  return klass.Ptr();
+  return klass;
 }
 
 typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
@@ -2282,7 +2276,7 @@
                                                 const char* descriptor,
                                                 size_t hash,
                                                 Handle<mirror::ClassLoader> class_loader,
-                                                ObjPtr<mirror::Class>* result) {
+                                                /*out*/ ObjPtr<mirror::Class>* result) {
   // Termination case: boot class loader.
   if (IsBootClassLoader(soa, class_loader.Get())) {
     *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
@@ -2535,7 +2529,7 @@
     if (old == nullptr) {
       old = result_ptr;  // For the comparison below, after releasing the lock.
       if (descriptor_equals) {
-        class_table->InsertWithHash(result_ptr.Ptr(), hash);
+        class_table->InsertWithHash(result_ptr, hash);
         Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
       }  // else throw below, after releasing the lock.
     }
@@ -2563,8 +2557,8 @@
         DescriptorToDot(descriptor).c_str());
     return nullptr;
   }
-  // success, return mirror::Class*
-  return result_ptr.Ptr();
+  // Success.
+  return result_ptr;
 }
 
 ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
@@ -2730,52 +2724,50 @@
 
 uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
                                                        const DexFile::ClassDef& dex_class_def) {
-  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
   size_t num_ref = 0;
   size_t num_8 = 0;
   size_t num_16 = 0;
   size_t num_32 = 0;
   size_t num_64 = 0;
-  if (class_data != nullptr) {
-    // We allow duplicate definitions of the same field in a class_data_item
-    // but ignore the repeated indexes here, b/21868015.
-    uint32_t last_field_idx = dex::kDexNoIndex;
-    for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) {
-      uint32_t field_idx = it.GetMemberIndex();
-      // Ordering enforced by DexFileVerifier.
-      DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx);
-      if (UNLIKELY(field_idx == last_field_idx)) {
-        continue;
-      }
-      last_field_idx = field_idx;
-      const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
-      const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
-      char c = descriptor[0];
-      switch (c) {
-        case 'L':
-        case '[':
-          num_ref++;
-          break;
-        case 'J':
-        case 'D':
-          num_64++;
-          break;
-        case 'I':
-        case 'F':
-          num_32++;
-          break;
-        case 'S':
-        case 'C':
-          num_16++;
-          break;
-        case 'B':
-        case 'Z':
-          num_8++;
-          break;
-        default:
-          LOG(FATAL) << "Unknown descriptor: " << c;
-          UNREACHABLE();
-      }
+  ClassAccessor accessor(dex_file, dex_class_def);
+  // We allow duplicate definitions of the same field in a class_data_item
+  // but ignore the repeated indexes here, b/21868015.
+  uint32_t last_field_idx = dex::kDexNoIndex;
+  for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
+    uint32_t field_idx = field.GetIndex();
+    // Ordering enforced by DexFileVerifier.
+    DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx);
+    if (UNLIKELY(field_idx == last_field_idx)) {
+      continue;
+    }
+    last_field_idx = field_idx;
+    const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+    const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
+    char c = descriptor[0];
+    switch (c) {
+      case 'L':
+      case '[':
+        num_ref++;
+        break;
+      case 'J':
+      case 'D':
+        num_64++;
+        break;
+      case 'I':
+      case 'F':
+        num_32++;
+        break;
+      case 'S':
+      case 'C':
+        num_16++;
+        break;
+      case 'B':
+      case 'Z':
+        num_8++;
+        break;
+      default:
+        LOG(FATAL) << "Unknown descriptor: " << c;
+        UNREACHABLE();
     }
   }
   return mirror::Class::ComputeClassSize(false,
@@ -2873,17 +2865,15 @@
   const DexFile& dex_file = klass->GetDexFile();
   const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
   CHECK(dex_class_def != nullptr);
-  const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
+  ClassAccessor accessor(dex_file, *dex_class_def);
   // There should always be class data if there were direct methods.
-  CHECK(class_data != nullptr) << klass->PrettyDescriptor();
-  ClassDataItemIterator it(dex_file, class_data);
-  it.SkipAllFields();
+  CHECK(accessor.HasClassData()) << klass->PrettyDescriptor();
   bool has_oat_class;
   OatFile::OatClass oat_class = OatFile::FindOatClass(dex_file,
                                                       klass->GetDexClassDefIndex(),
                                                       &has_oat_class);
   // Link the code of methods skipped by LinkCode.
-  for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) {
+  for (size_t method_index = 0; method_index < accessor.NumDirectMethods(); ++method_index) {
     ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_);
     if (!method->IsStatic()) {
       // Only update static methods.
@@ -2992,17 +2982,6 @@
   klass->SetDexTypeIndex(dex_class_def.class_idx_);
 }
 
-void ClassLinker::LoadClass(Thread* self,
-                            const DexFile& dex_file,
-                            const DexFile::ClassDef& dex_class_def,
-                            Handle<mirror::Class> klass) {
-  const uint8_t* class_data = dex_file.GetClassData(dex_class_def);
-  if (class_data == nullptr) {
-    return;  // no fields or methods - for example a marker interface
-  }
-  LoadClassMembers(self, dex_file, class_data, klass);
-}
-
 LengthPrefixedArray<ArtField>* ClassLinker::AllocArtFieldArray(Thread* self,
                                                                LinearAlloc* allocator,
                                                                size_t length) {
@@ -3061,10 +3040,15 @@
   return allocator;
 }
 
-void ClassLinker::LoadClassMembers(Thread* self,
-                                   const DexFile& dex_file,
-                                   const uint8_t* class_data,
-                                   Handle<mirror::Class> klass) {
+void ClassLinker::LoadClass(Thread* self,
+                            const DexFile& dex_file,
+                            const DexFile::ClassDef& dex_class_def,
+                            Handle<mirror::Class> klass) {
+  ClassAccessor accessor(dex_file, dex_class_def);
+  if (!accessor.HasClassData()) {
+    return;
+  }
+  Runtime* const runtime = Runtime::Current();
   {
     // Note: We cannot have thread suspension until the field and method arrays are setup or else
     // Class::VisitFieldRoots may miss some fields or methods.
@@ -3073,45 +3057,79 @@
     // We allow duplicate definitions of the same field in a class_data_item
     // but ignore the repeated indexes here, b/21868015.
     LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader());
-    ClassDataItemIterator it(dex_file, class_data);
     LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self,
                                                                 allocator,
-                                                                it.NumStaticFields());
-    size_t num_sfields = 0;
-    uint32_t last_field_idx = 0u;
-    for (; it.HasNextStaticField(); it.Next()) {
-      uint32_t field_idx = it.GetMemberIndex();
-      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
-      if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) {
-        DCHECK_LT(num_sfields, it.NumStaticFields());
-        LoadField(it, klass, &sfields->At(num_sfields));
-        ++num_sfields;
-        last_field_idx = field_idx;
-      }
-    }
-
-    // Load instance fields.
+                                                                accessor.NumStaticFields());
     LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self,
                                                                 allocator,
-                                                                it.NumInstanceFields());
+                                                                accessor.NumInstanceFields());
+    size_t num_sfields = 0u;
     size_t num_ifields = 0u;
-    last_field_idx = 0u;
-    for (; it.HasNextInstanceField(); it.Next()) {
-      uint32_t field_idx = it.GetMemberIndex();
-      DCHECK_GE(field_idx, last_field_idx);  // Ordering enforced by DexFileVerifier.
-      if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) {
-        DCHECK_LT(num_ifields, it.NumInstanceFields());
-        LoadField(it, klass, &ifields->At(num_ifields));
-        ++num_ifields;
-        last_field_idx = field_idx;
-      }
-    }
+    uint32_t last_static_field_idx = 0u;
+    uint32_t last_instance_field_idx = 0u;
 
-    if (UNLIKELY(num_sfields != it.NumStaticFields()) ||
-        UNLIKELY(num_ifields != it.NumInstanceFields())) {
+    // Methods
+    bool has_oat_class = false;
+    const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler())
+        ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
+        : OatFile::OatClass::Invalid();
+    const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
+    klass->SetMethodsPtr(
+        AllocArtMethodArray(self, allocator, accessor.NumMethods()),
+        accessor.NumDirectMethods(),
+        accessor.NumVirtualMethods());
+    size_t class_def_method_index = 0;
+    uint32_t last_dex_method_index = dex::kDexNoIndex;
+    size_t last_class_def_method_index = 0;
+
+    // Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the
+    // methods needs to decode all of the fields.
+    accessor.VisitFieldsAndMethods([&](
+        const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+          uint32_t field_idx = field.GetIndex();
+          DCHECK_GE(field_idx, last_static_field_idx);  // Ordering enforced by DexFileVerifier.
+          if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) {
+            LoadField(field, klass, &sfields->At(num_sfields));
+            ++num_sfields;
+            last_static_field_idx = field_idx;
+          }
+        }, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) {
+          uint32_t field_idx = field.GetIndex();
+          DCHECK_GE(field_idx, last_instance_field_idx);  // Ordering enforced by DexFileVerifier.
+          if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) {
+            LoadField(field, klass, &ifields->At(num_ifields));
+            ++num_ifields;
+            last_instance_field_idx = field_idx;
+          }
+        }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
+          ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index,
+              image_pointer_size_);
+          LoadMethod(dex_file, method, klass, art_method);
+          LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+          uint32_t it_method_index = method.GetIndex();
+          if (last_dex_method_index == it_method_index) {
+            // duplicate case
+            art_method->SetMethodIndex(last_class_def_method_index);
+          } else {
+            art_method->SetMethodIndex(class_def_method_index);
+            last_dex_method_index = it_method_index;
+            last_class_def_method_index = class_def_method_index;
+          }
+          ++class_def_method_index;
+        }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) {
+          ArtMethod* art_method = klass->GetVirtualMethodUnchecked(
+              class_def_method_index - accessor.NumDirectMethods(),
+              image_pointer_size_);
+          LoadMethod(dex_file, method, klass, art_method);
+          LinkCode(this, art_method, oat_class_ptr, class_def_method_index);
+          ++class_def_method_index;
+        });
+
+    if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) {
       LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor()
-          << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields()
-          << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")";
+          << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields()
+          << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields()
+          << ")";
       // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size.
       if (sfields != nullptr) {
         sfields->SetSize(num_sfields);
@@ -3125,87 +3143,49 @@
     DCHECK_EQ(klass->NumStaticFields(), num_sfields);
     klass->SetIFieldsPtr(ifields);
     DCHECK_EQ(klass->NumInstanceFields(), num_ifields);
-    // Load methods.
-    bool has_oat_class = false;
-    const OatFile::OatClass oat_class =
-        (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler())
-            ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class)
-            : OatFile::OatClass::Invalid();
-    const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr;
-    klass->SetMethodsPtr(
-        AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()),
-        it.NumDirectMethods(),
-        it.NumVirtualMethods());
-    size_t class_def_method_index = 0;
-    uint32_t last_dex_method_index = dex::kDexNoIndex;
-    size_t last_class_def_method_index = 0;
-    // TODO These should really use the iterators.
-    for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
-      ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
-      LoadMethod(dex_file, it, klass, method);
-      LinkCode(this, method, oat_class_ptr, class_def_method_index);
-      uint32_t it_method_index = it.GetMemberIndex();
-      if (last_dex_method_index == it_method_index) {
-        // duplicate case
-        method->SetMethodIndex(last_class_def_method_index);
-      } else {
-        method->SetMethodIndex(class_def_method_index);
-        last_dex_method_index = it_method_index;
-        last_class_def_method_index = class_def_method_index;
-      }
-      class_def_method_index++;
-    }
-    for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
-      ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
-      LoadMethod(dex_file, it, klass, method);
-      DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
-      LinkCode(this, method, oat_class_ptr, class_def_method_index);
-      class_def_method_index++;
-    }
-    DCHECK(!it.HasNext());
   }
   // Ensure that the card is marked so that remembered sets pick up native roots.
   Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get());
   self->AllowThreadSuspension();
 }
 
-void ClassLinker::LoadField(const ClassDataItemIterator& it,
+void ClassLinker::LoadField(const ClassAccessor::Field& field,
                             Handle<mirror::Class> klass,
                             ArtField* dst) {
-  const uint32_t field_idx = it.GetMemberIndex();
+  const uint32_t field_idx = field.GetIndex();
   dst->SetDexFieldIndex(field_idx);
   dst->SetDeclaringClass(klass.Get());
 
   // Get access flags from the DexFile. If this is a boot class path class,
   // also set its runtime hidden API access flags.
-  uint32_t access_flags = it.GetFieldAccessFlags();
+  uint32_t access_flags = field.GetAccessFlags();
   if (klass->IsBootStrapClassLoaded()) {
     access_flags =
-        HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags());
+        HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags());
   }
   dst->SetAccessFlags(access_flags);
 }
 
 void ClassLinker::LoadMethod(const DexFile& dex_file,
-                             const ClassDataItemIterator& it,
+                             const ClassAccessor::Method& method,
                              Handle<mirror::Class> klass,
                              ArtMethod* dst) {
-  uint32_t dex_method_idx = it.GetMemberIndex();
+  const uint32_t dex_method_idx = method.GetIndex();
   const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
 
   ScopedAssertNoThreadSuspension ants("LoadMethod");
   dst->SetDexMethodIndex(dex_method_idx);
   dst->SetDeclaringClass(klass.Get());
-  dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
+  dst->SetCodeItemOffset(method.GetCodeItemOffset());
 
   // Get access flags from the DexFile. If this is a boot class path class,
   // also set its runtime hidden API access flags.
-  uint32_t access_flags = it.GetMethodAccessFlags();
+  uint32_t access_flags = method.GetAccessFlags();
 
   if (klass->IsBootStrapClassLoaded()) {
     access_flags =
-        HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags());
+        HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags());
   }
 
   if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
@@ -3553,6 +3533,10 @@
   return h_class.Get();
 }
 
+inline ObjPtr<mirror::IfTable> ClassLinker::GetArrayIfTable() {
+  return GetClassRoot<mirror::ObjectArray<mirror::Object>>(this)->GetIfTable();
+}
+
 // Create an array class (i.e. the class object for the array, not the
 // array itself).  "descriptor" looks like "[C" or "[[[[B" or
 // "[Ljava/lang/String;".
@@ -3612,7 +3596,7 @@
     ObjPtr<mirror::Class> new_class =
         LookupClass(self, descriptor, hash, component_type->GetClassLoader());
     if (new_class != nullptr) {
-      return new_class.Ptr();
+      return new_class;
     }
   }
 
@@ -3680,7 +3664,7 @@
   // Use the single, global copies of "interfaces" and "iftable"
   // (remember not to free them for arrays).
   {
-    ObjPtr<mirror::IfTable> array_iftable = array_iftable_.Read();
+    ObjPtr<mirror::IfTable> array_iftable = GetArrayIfTable();
     CHECK(array_iftable != nullptr);
     new_class->SetIfTable(array_iftable);
   }
@@ -3713,7 +3697,7 @@
   //
   // (Yes, this happens.)
 
-  return existing.Ptr();
+  return existing;
 }
 
 ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) {
@@ -3763,7 +3747,7 @@
     ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
     ObjPtr<mirror::Class> existing = class_table->Lookup(descriptor, hash);
     if (existing != nullptr) {
-      return existing.Ptr();
+      return existing;
     }
     VerifyObject(klass);
     class_table->InsertWithHash(klass, hash);
@@ -3817,7 +3801,7 @@
   if (class_table != nullptr) {
     ObjPtr<mirror::Class> result = class_table->Lookup(descriptor, hash);
     if (result != nullptr) {
-      return result.Ptr();
+      return result;
     }
   }
   return nullptr;
@@ -4772,24 +4756,29 @@
                                                                  this,
                                                                  *dex_class_def);
     const DexFile& dex_file = *dex_cache->GetDexFile();
-    const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
-    ClassDataItemIterator field_it(dex_file, class_data);
+
     if (value_it.HasNext()) {
-      DCHECK(field_it.HasNextStaticField());
+      ClassAccessor accessor(dex_file, *dex_class_def);
       CHECK(can_init_statics);
-      for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) {
-        ArtField* field = ResolveField(
-            field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true);
+      for (const ClassAccessor::Field& field : accessor.GetStaticFields()) {
+        if (!value_it.HasNext()) {
+          break;
+        }
+        ArtField* art_field = ResolveField(field.GetIndex(),
+                                           dex_cache,
+                                           class_loader,
+                                           /* is_static */ true);
         if (Runtime::Current()->IsActiveTransaction()) {
-          value_it.ReadValueToField<true>(field);
+          value_it.ReadValueToField<true>(art_field);
         } else {
-          value_it.ReadValueToField<false>(field);
+          value_it.ReadValueToField<false>(art_field);
         }
         if (self->IsExceptionPending()) {
           break;
         }
-        DCHECK(!value_it.HasNext() || field_it.HasNextStaticField());
+        value_it.Next();
       }
+      DCHECK(self->IsExceptionPending() || !value_it.HasNext());
     }
   }
 
@@ -5723,8 +5712,8 @@
         klass->SetVTable(super_vtable);
         return true;
       }
-      vtable = hs.NewHandle(down_cast<mirror::PointerArray*>(
-          super_vtable->CopyOf(self, max_count)));
+      vtable = hs.NewHandle(
+          ObjPtr<mirror::PointerArray>::DownCast(super_vtable->CopyOf(self, max_count)));
       if (UNLIKELY(vtable == nullptr)) {
         self->AssertPendingOOMException();
         return false;
@@ -5860,7 +5849,7 @@
     // Shrink vtable if possible
     CHECK_LE(actual_count, max_count);
     if (actual_count < max_count) {
-      vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, actual_count)));
+      vtable.Assign(ObjPtr<mirror::PointerArray>::DownCast(vtable->CopyOf(self, actual_count)));
       if (UNLIKELY(vtable == nullptr)) {
         self->AssertPendingOOMException();
         return false;
@@ -5874,7 +5863,7 @@
                             static_cast<int>(num_virtual_methods));
       return false;
     }
-    auto* vtable = AllocPointerArray(self, num_virtual_methods);
+    ObjPtr<mirror::PointerArray> vtable = AllocPointerArray(self, num_virtual_methods);
     if (UNLIKELY(vtable == nullptr)) {
       self->AssertPendingOOMException();
       return false;
@@ -6118,7 +6107,8 @@
         DCHECK(if_table != nullptr);
         DCHECK(if_table->GetMethodArray(i) != nullptr);
         // If we are working on a super interface, try extending the existing method array.
-        method_array = down_cast<mirror::PointerArray*>(if_table->GetMethodArray(i)->Clone(self));
+        method_array = ObjPtr<mirror::PointerArray>::DownCast(MakeObjPtr(
+            if_table->GetMethodArray(i)->Clone(self)));
       } else {
         method_array = AllocPointerArray(self, num_methods);
       }
@@ -6382,7 +6372,7 @@
 // iftable must be large enough to hold all interfaces without changing its size.
 static size_t FillIfTable(ObjPtr<mirror::IfTable> iftable,
                           size_t super_ifcount,
-                          std::vector<mirror::Class*> to_process)
+                          std::vector<ObjPtr<mirror::Class>> to_process)
     REQUIRES(Roles::uninterruptible_)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   // This is the set of all class's already in the iftable. Used to make checking if a class has
@@ -6522,11 +6512,11 @@
   size_t new_ifcount;
   {
     ScopedAssertNoThreadSuspension nts("Copying mirror::Class*'s for FillIfTable");
-    std::vector<mirror::Class*> to_add;
+    std::vector<ObjPtr<mirror::Class>> to_add;
     for (size_t i = 0; i < num_interfaces; i++) {
       ObjPtr<mirror::Class> interface = have_interfaces ? interfaces->Get(i) :
           mirror::Class::GetDirectInterface(self, klass.Get(), i);
-      to_add.push_back(interface.Ptr());
+      to_add.push_back(interface);
     }
 
     new_ifcount = FillIfTable(iftable.Get(), super_ifcount, std::move(to_add));
@@ -6537,7 +6527,7 @@
   // Shrink iftable in case duplicates were found
   if (new_ifcount < ifcount) {
     DCHECK_NE(num_interfaces, 0U);
-    iftable.Assign(down_cast<mirror::IfTable*>(
+    iftable.Assign(ObjPtr<mirror::IfTable>::DownCast(
         iftable->CopyOf(self, new_ifcount * mirror::IfTable::kMax)));
     if (UNLIKELY(iftable == nullptr)) {
       self->AssertPendingOOMException();
@@ -7051,7 +7041,7 @@
                                   default_conflict_methods_.size();
 
   ObjPtr<mirror::PointerArray> vtable =
-      down_cast<mirror::PointerArray*>(old_vtable->CopyOf(self_, new_vtable_count));
+      ObjPtr<mirror::PointerArray>::DownCast(old_vtable->CopyOf(self_, new_vtable_count));
   if (UNLIKELY(vtable == nullptr)) {
     self_->AssertPendingOOMException();
     return nullptr;
@@ -7664,14 +7654,15 @@
   klass->SetReferenceInstanceOffsets(reference_offsets);
 }
 
-ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx,
-                                                  Handle<mirror::DexCache> dex_cache) {
-  DCHECK(dex_cache != nullptr);
-  Thread::PoisonObjectPointersIfDebug();
-  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
-  if (resolved != nullptr) {
-    return resolved;
-  }
+ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx,
+                                                    ObjPtr<mirror::DexCache> dex_cache) {
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache));
+  return DoResolveString(string_idx, h_dex_cache);
+}
+
+ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx,
+                                                    Handle<mirror::DexCache> dex_cache) {
   const DexFile& dex_file = *dex_cache->GetDexFile();
   uint32_t utf16_length;
   const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
@@ -7682,13 +7673,9 @@
   return string;
 }
 
-ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx,
-                                                 ObjPtr<mirror::DexCache> dex_cache) {
+ObjPtr<mirror::String> ClassLinker::DoLookupString(dex::StringIndex string_idx,
+                                                   ObjPtr<mirror::DexCache> dex_cache) {
   DCHECK(dex_cache != nullptr);
-  ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx);
-  if (resolved != nullptr) {
-    return resolved;
-  }
   const DexFile& dex_file = *dex_cache->GetDexFile();
   uint32_t utf16_length;
   const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
@@ -7721,7 +7708,7 @@
     DCHECK(self != nullptr);
     const size_t hash = ComputeModifiedUtf8Hash(descriptor);
     // Find the class in the loaded classes table.
-    type = LookupClass(self, descriptor, hash, class_loader.Ptr());
+    type = LookupClass(self, descriptor, hash, class_loader);
   }
   if (type != nullptr) {
     if (type->IsResolved()) {
@@ -8104,7 +8091,7 @@
 
   ObjPtr<mirror::MethodType> resolved = dex_cache->GetResolvedMethodType(proto_idx);
   if (resolved != nullptr) {
-    return resolved.Ptr();
+    return resolved;
   }
 
   StackHandleScope<4> hs(self);
@@ -8760,7 +8747,7 @@
   DCHECK(dex_file != nullptr);
   Thread* const self = Thread::Current();
   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
-  ClassTable* const table = ClassTableForClassLoader(class_loader.Ptr());
+  ClassTable* const table = ClassTableForClassLoader(class_loader);
   DCHECK(table != nullptr);
   if (table->InsertStrongRoot(dex_file) && class_loader != nullptr) {
     // It was not already inserted, perform the write barrier to let the GC know the class loader's
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 32016fa..30c2423 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,6 +27,7 @@
 #include "base/enums.h"
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "dex/class_accessor.h"
 #include "dex/dex_cache_resolved_classes.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_types.h"
@@ -163,7 +164,7 @@
   }
 
   // Finds the array class given for the element class.
-  ObjPtr<mirror::Class> FindArrayClass(Thread* self, ObjPtr<mirror::Class>* element_class)
+  ObjPtr<mirror::Class> FindArrayClass(Thread* self, ObjPtr<mirror::Class> element_class)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
@@ -203,6 +204,16 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Resolve a String with the given index from the DexFile associated with the given `referrer`,
+  // storing the result in the DexCache. The `referrer` is used to identify the target DexCache
+  // to use for resolution.
+  ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx,
+                                       ArtField* referrer)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx,
+                                       ArtMethod* referrer)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Resolve a String with the given index from the DexFile associated with the given DexCache,
   // storing the result in the DexCache.
   ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx,
@@ -451,7 +462,7 @@
                                                       LinearAlloc* allocator,
                                                       size_t length);
 
-  mirror::PointerArray* AllocPointerArray(Thread* self, size_t length)
+  ObjPtr<mirror::PointerArray> AllocPointerArray(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
@@ -459,8 +470,8 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
-  mirror::ObjectArray<mirror::StackTraceElement>* AllocStackTraceElementArray(Thread* self,
-                                                                              size_t length)
+  ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> AllocStackTraceElementArray(Thread* self,
+                                                                                     size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
@@ -543,8 +554,9 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  mirror::ObjectArray<mirror::Class>* GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read<kReadBarrierOption>();
+  ObjPtr<mirror::ObjectArray<mirror::Class>> GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) {
+    ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots =
+        class_roots_.Read<kReadBarrierOption>();
     DCHECK(class_roots != nullptr);
     return class_roots;
   }
@@ -777,16 +789,16 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
-  mirror::DexCache* AllocDexCache(ObjPtr<mirror::String>* out_location,
-                                  Thread* self,
-                                  const DexFile& dex_file)
+  ObjPtr<mirror::DexCache> AllocDexCache(/*out*/ ObjPtr<mirror::String>* out_location,
+                                         Thread* self,
+                                         const DexFile& dex_file)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
   // Used for tests and AppendToBootClassPath.
-  mirror::DexCache* AllocAndInitializeDexCache(Thread* self,
-                                               const DexFile& dex_file,
-                                               LinearAlloc* linear_alloc)
+  ObjPtr<mirror::DexCache> AllocAndInitializeDexCache(Thread* self,
+                                                      const DexFile& dex_file,
+                                                      LinearAlloc* linear_alloc)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_)
       REQUIRES(!Roles::uninterruptible_);
@@ -824,18 +836,14 @@
                  const DexFile::ClassDef& dex_class_def,
                  Handle<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  void LoadClassMembers(Thread* self,
-                        const DexFile& dex_file,
-                        const uint8_t* class_data,
-                        Handle<mirror::Class> klass)
-      REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst)
+  void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void LoadMethod(const DexFile& dex_file,
-                  const ClassDataItemIterator& it,
-                  Handle<mirror::Class> klass, ArtMethod* dst)
+                  const ClassAccessor::Method& method,
+                  Handle<mirror::Class> klass,
+                  ArtMethod* dst)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void FixupStaticTrampolines(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -850,7 +858,7 @@
                                      const char* descriptor,
                                      size_t hash,
                                      Handle<mirror::ClassLoader> class_loader,
-                                     ObjPtr<mirror::Class>* result)
+                                     /*out*/ ObjPtr<mirror::Class>* result)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
@@ -884,6 +892,19 @@
                                              ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Implementation of ResolveString() called when the string was not found in the dex cache.
+  ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx,
+                                         ObjPtr<mirror::DexCache> dex_cache)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx,
+                                         Handle<mirror::DexCache> dex_cache)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Implementation of LookupString() called when the string was not found in the dex cache.
+  ObjPtr<mirror::String> DoLookupString(dex::StringIndex string_idx,
+                                        ObjPtr<mirror::DexCache> dex_cache)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Implementation of ResolveType() called when the type was not found in the dex cache.
   ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx,
                                       ObjPtr<mirror::Class> referrer)
@@ -1251,6 +1272,8 @@
                                 ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  ObjPtr<mirror::IfTable> GetArrayIfTable() REQUIRES_SHARED(Locks::mutator_lock_);
+
   std::vector<const DexFile*> boot_class_path_;
   std::vector<std::unique_ptr<const DexFile>> boot_dex_files_;
 
@@ -1280,9 +1303,6 @@
   // Well known mirror::Class roots.
   GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_;
 
-  // The interface table used by all arrays.
-  GcRoot<mirror::IfTable> array_iftable_;
-
   // A cache of the last FindArrayClass results. The cache serves to avoid creating array class
   // descriptors for the sake of performing FindClass.
   static constexpr size_t kFindArrayCacheSize = 16;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 5d420aa..e40f1db 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -233,8 +233,7 @@
     ObjPtr<mirror::Class> direct_interface1 =
         mirror::Class::GetDirectInterface(self, array.Get(), 1);
     EXPECT_STREQ(direct_interface1->GetDescriptor(&temp), "Ljava/io/Serializable;");
-    ObjPtr<mirror::Class> array_ptr = array->GetComponentType();
-    EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, &array_ptr), array.Get());
+    EXPECT_OBJ_PTR_EQ(class_linker_->FindArrayClass(self, array->GetComponentType()), array.Get());
 
     PointerSize pointer_size = class_linker_->GetImagePointerSize();
     ObjPtr<mirror::Class> JavaLangObject =
diff --git a/runtime/class_root.h b/runtime/class_root.h
index 5c78198..4aa9801 100644
--- a/runtime/class_root.h
+++ b/runtime/class_root.h
@@ -127,7 +127,7 @@
   ObjPtr<mirror::Class> klass =
       class_roots->GetWithoutChecks<kDefaultVerifyFlags, kReadBarrierOption>(index);
   DCHECK(klass != nullptr);
-  return klass.Ptr();
+  return klass;
 }
 
 template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc
index c5bb4d5..cb334b5 100644
--- a/runtime/debug_print.cc
+++ b/runtime/debug_print.cc
@@ -37,7 +37,7 @@
   std::ostringstream oss;
   gc::Heap* heap = Runtime::Current()->GetHeap();
   gc::space::ContinuousSpace* cs =
-      heap->FindContinuousSpaceFromObject(klass.Ptr(), /* fail_ok */ true);
+      heap->FindContinuousSpaceFromObject(klass, /* fail_ok */ true);
   if (cs != nullptr) {
     if (cs->IsImageSpace()) {
       gc::space::ImageSpace* ispace = cs->AsImageSpace();
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 88628bb..f75f47c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1388,7 +1388,7 @@
     *new_object_id = 0;
     return JDWP::ERR_OUT_OF_MEMORY;
   }
-  *new_object_id = gRegistry->Add(new_object.Ptr());
+  *new_object_id = gRegistry->Add(new_object);
   return JDWP::ERR_NONE;
 }
 
@@ -1404,10 +1404,9 @@
     return error;
   }
   Thread* self = Thread::Current();
-  gc::Heap* heap = Runtime::Current()->GetHeap();
-  mirror::Array* new_array = mirror::Array::Alloc<true>(self, c, length,
-                                                        c->GetComponentSizeShift(),
-                                                        heap->GetCurrentAllocator());
+  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
+  ObjPtr<mirror::Array> new_array =
+      mirror::Array::Alloc<true>(self, c, length, c->GetComponentSizeShift(), allocator_type);
   if (new_array == nullptr) {
     DCHECK(self->IsExceptionPending());
     self->ClearException();
@@ -1849,7 +1848,7 @@
       return field_value;
 
     case Primitive::kPrimNot:
-      field_value.SetL(f->GetObject(o).Ptr());
+      field_value.SetL(f->GetObject(o));
       return field_value;
 
     case Primitive::kPrimVoid:
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 5cb08dc..9358cbe 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -359,7 +359,7 @@
   ObjPtr<mirror::Class> annotation_member_class =
       soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember);
   ObjPtr<mirror::Class> annotation_member_array_class =
-      class_linker->FindArrayClass(self, &annotation_member_class);
+      class_linker->FindArrayClass(self, annotation_member_class);
   if (annotation_member_array_class == nullptr) {
     return nullptr;
   }
@@ -967,7 +967,7 @@
   ObjPtr<mirror::Class> annotation_array_class =
       soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
   ObjPtr<mirror::Class> annotation_array_array_class =
-      Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
+      Runtime::Current()->GetClassLinker()->FindArrayClass(self, annotation_array_class);
   if (annotation_array_array_class == nullptr) {
     return nullptr;
   }
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index f6b1c73..022857a 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -268,14 +268,14 @@
 // check.
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
-                                         int32_t component_count,
-                                         ArtMethod* method,
-                                         Thread* self,
-                                         gc::AllocatorType allocator_type) {
+inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
+                                                int32_t component_count,
+                                                ArtMethod* method,
+                                                Thread* self,
+                                                gc::AllocatorType allocator_type) {
   bool slow_path = false;
-  mirror::Class* klass = CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method,
-                                                       &slow_path);
+  ObjPtr<mirror::Class> klass =
+      CheckArrayAlloc<kAccessCheck>(type_idx, component_count, method, &slow_path);
   if (UNLIKELY(slow_path)) {
     if (klass == nullptr) {
       return nullptr;
@@ -306,7 +306,7 @@
   // No need to retry a slow-path allocation as the above code won't cause a GC or thread
   // suspension.
   return mirror::Array::Alloc<kInstrumented>(self, klass, component_count,
-                                             klass->GetComponentSizeShift(), allocator_type);
+                                             klass->GetComponentSizeShift(), allocator_type).Ptr();
 }
 
 template<FindFieldType type, bool access_check>
@@ -743,33 +743,6 @@
   return h_class.Get();
 }
 
-static inline ObjPtr<mirror::String> ResolveString(ClassLinker* class_linker,
-                                                   dex::StringIndex string_idx,
-                                                   ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  Thread::PoisonObjectPointersIfDebug();
-  ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx);
-  if (UNLIKELY(string == nullptr)) {
-    StackHandleScope<1> hs(Thread::Current());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
-    string = class_linker->ResolveString(string_idx, dex_cache);
-  }
-  return string;
-}
-
-inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
-                                                    dex::StringIndex string_idx) {
-  Thread::PoisonObjectPointersIfDebug();
-  ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx);
-  if (UNLIKELY(string == nullptr)) {
-    StackHandleScope<1> hs(Thread::Current());
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    string = class_linker->ResolveString(string_idx, dex_cache);
-  }
-  return string;
-}
-
 inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) {
   // Save any pending exception over monitor exit call.
   mirror::Throwable* saved_exception = nullptr;
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index e33de9c..9d70b03 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -87,11 +87,11 @@
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
 template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
-                                                       int32_t component_count,
-                                                       ArtMethod* method,
-                                                       Thread* self,
-                                                       gc::AllocatorType allocator_type)
+ALWAYS_INLINE inline ObjPtr<mirror::Array> AllocArrayFromCode(dex::TypeIndex type_idx,
+                                                              int32_t component_count,
+                                                              ArtMethod* method,
+                                                              Thread* self,
+                                                              gc::AllocatorType allocator_type)
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
@@ -162,11 +162,6 @@
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
-inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer,
-                                                    dex::StringIndex string_idx)
-    REQUIRES_SHARED(Locks::mutator_lock_)
-    REQUIRES(!Roles::uninterruptible_);
-
 // TODO: annotalysis disabled as monitor semantics are maintained in Java code.
 inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
     NO_THREAD_SAFETY_ANALYSIS REQUIRES(!Roles::uninterruptible_);
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index fa536c7..6275612 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -210,7 +210,8 @@
   auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self,
                                                                   CalleeSaveType::kSaveEverything);
   ArtMethod* caller = caller_and_outer.caller;
-  ObjPtr<mirror::String> result = ResolveStringFromCode(caller, dex::StringIndex(string_idx));
+  ObjPtr<mirror::String> result =
+      Runtime::Current()->GetClassLinker()->ResolveString(dex::StringIndex(string_idx), caller);
   if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) {
     StoreStringInBss(caller_and_outer.outer_method, dex::StringIndex(string_idx), result);
   }
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 4f06ee6..3869533 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -35,7 +35,7 @@
   VerificationTest() {}
 
   template <class T>
-  mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
+  ObjPtr<mirror::ObjectArray<T>> AllocObjectArray(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return mirror::ObjectArray<T>::Alloc(
         self,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index dbe09e8..e754fbc 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1287,7 +1287,7 @@
       bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor);
       // Fixup image roots.
       CHECK(app_image.InSource(reinterpret_cast<uintptr_t>(
-          image_header.GetImageRoots<kWithoutReadBarrier>())));
+          image_header.GetImageRoots<kWithoutReadBarrier>().Ptr())));
       image_header.RelocateImageObjects(app_image.Delta());
       CHECK_EQ(image_header.GetImageBegin(), target_base);
       // Fix up dex cache DexFile pointers.
diff --git a/runtime/image-inl.h b/runtime/image-inl.h
index 3a66a34..c527f6f 100644
--- a/runtime/image-inl.h
+++ b/runtime/image-inl.h
@@ -23,18 +23,19 @@
 #include "imt_conflict_table.h"
 #include "imtable.h"
 #include "mirror/object_array-inl.h"
+#include "obj_ptr-inl.h"
 #include "read_barrier-inl.h"
 
 namespace art {
 
 template <ReadBarrierOption kReadBarrierOption>
-inline mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const {
-  mirror::ObjectArray<mirror::Object>* image_roots = GetImageRoots<kReadBarrierOption>();
+inline ObjPtr<mirror::Object> ImageHeader::GetImageRoot(ImageRoot image_root) const {
+  ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots = GetImageRoots<kReadBarrierOption>();
   return image_roots->Get<kVerifyNone, kReadBarrierOption>(static_cast<int32_t>(image_root));
 }
 
 template <ReadBarrierOption kReadBarrierOption>
-inline mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const {
+inline ObjPtr<mirror::ObjectArray<mirror::Object>> ImageHeader::GetImageRoots() const {
   // Need a read barrier as it's not visited during root scan.
   // Pass in the address of the local variable to the read barrier
   // rather than image_roots_ because it won't move (asserted below)
diff --git a/runtime/image.cc b/runtime/image.cc
index 7ad2e7b..17fc664 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '0', '\0' };  // ClassRoot::MethodHandle.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '1', '\0' };  // Pre-allocated Throwables.
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/image.h b/runtime/image.h
index 8acd5bc..c6fc052 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -27,6 +27,7 @@
 
 class ArtField;
 class ArtMethod;
+template <class MirrorType> class ObjPtr;
 
 namespace linker {
 class ImageWriter;
@@ -206,7 +207,11 @@
   enum ImageRoot {
     kDexCaches,
     kClassRoots,
-    kClassLoader,  // App image only.
+    kOomeWhenThrowingException,       // Pre-allocated OOME when throwing exception.
+    kOomeWhenThrowingOome,            // Pre-allocated OOME when throwing OOME.
+    kOomeWhenHandlingStackOverflow,   // Pre-allocated OOME when handling StackOverflowError.
+    kNoClassDefFoundError,            // Pre-allocated NoClassDefFoundError.
+    kClassLoader,                     // App image only.
     kImageRootsMax,
   };
 
@@ -277,11 +282,11 @@
   }
 
   template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  mirror::Object* GetImageRoot(ImageRoot image_root) const
+  ObjPtr<mirror::Object> GetImageRoot(ImageRoot image_root) const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
-  mirror::ObjectArray<mirror::Object>* GetImageRoots() const
+  ObjPtr<mirror::ObjectArray<mirror::Object>> GetImageRoots() const
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void RelocateImage(off_t delta);
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 9673bd9..2128f8c 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -111,12 +111,12 @@
   if (serial_ == kIRTPrevCount) {
     serial_ = 0;
   }
-  references_[serial_] = GcRoot<mirror::Object>(obj.Ptr());
+  references_[serial_] = GcRoot<mirror::Object>(obj);
 }
 
 inline void IrtEntry::SetReference(ObjPtr<mirror::Object> obj) {
   DCHECK_LT(serial_, kIRTPrevCount);
-  references_[serial_] = GcRoot<mirror::Object>(obj.Ptr());
+  references_[serial_] = GcRoot<mirror::Object>(obj);
 }
 
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 90e89cf..27f761a 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -945,11 +945,9 @@
       return true;
     }
     case EncodedArrayValueIterator::ValueType::kString: {
-      StackHandleScope<1> hs(self);
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
       dex::StringIndex index(static_cast<uint32_t>(encoded_value->GetI()));
       ClassLinker* cl = Runtime::Current()->GetClassLinker();
-      ObjPtr<mirror::String> o = cl->ResolveString(index, dex_cache);
+      ObjPtr<mirror::String> o = cl->ResolveString(index, referrer);
       if (UNLIKELY(o.IsNull())) {
         DCHECK(self->IsExceptionPending());
         return false;
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0ee780d..60bf505 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -340,12 +340,8 @@
     }
   }
   ArtMethod* method = shadow_frame.GetMethod();
-  ObjPtr<mirror::String> string_ptr = method->GetDexCache()->GetResolvedString(string_idx);
-  if (UNLIKELY(string_ptr == nullptr)) {
-    StackHandleScope<1> hs(self);
-    Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
-    string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(string_idx, dex_cache);
-  }
+  ObjPtr<mirror::String> string_ptr =
+      Runtime::Current()->GetClassLinker()->ResolveString(string_idx, method);
   return string_ptr;
 }
 
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index d62f511..e4cc6d3 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -559,7 +559,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const Instruction* inst = Instruction::At(dex_pc_ptr);
   int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
-  mirror::Object* obj = AllocArrayFromCode<false, true>(
+  ObjPtr<mirror::Object> obj = AllocArrayFromCode<false, true>(
       dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
       Runtime::Current()->GetHeap()->GetCurrentAllocator());
   if (UNLIKELY(obj == nullptr)) {
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 7abb007..667bd03 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1691,7 +1691,7 @@
   ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Object*>(args[0])->AsClass();
   Runtime* runtime = Runtime::Current();
   ObjPtr<mirror::Class> array_class =
-      runtime->GetClassLinker()->FindArrayClass(self, &element_class);
+      runtime->GetClassLinker()->FindArrayClass(self, element_class);
   DCHECK(array_class != nullptr);
   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
   result->SetL(mirror::Array::Alloc<true, true>(self,
@@ -1818,13 +1818,13 @@
   ObjPtr<mirror::Class> element_class = reinterpret_cast<mirror::Class*>(args[0])->AsClass();
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(self, &element_class);
+  ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(self, element_class);
   if (UNLIKELY(array_class == nullptr)) {
     CHECK(self->IsExceptionPending());
     return;
   }
   DCHECK(array_class->IsObjectArrayClass());
-  mirror::Array* new_array = mirror::ObjectArray<mirror::Object*>::Alloc(
+  ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object>::Alloc(
       self, array_class, length, runtime->GetHeap()->GetCurrentAllocator());
   result->SetL(new_array);
 }
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 449458c..655713e 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -91,7 +91,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_) {
     Runtime* runtime = Runtime::Current();
     ObjPtr<mirror::Class> array_type =
-        runtime->GetClassLinker()->FindArrayClass(self, &component_type);
+        runtime->GetClassLinker()->FindArrayClass(self, component_type);
     CHECK(array_type != nullptr);
     ObjPtr<mirror::ObjectArray<mirror::Object>> result =
         mirror::ObjectArray<mirror::Object>::Alloc(self, array_type, 3);
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index d8aa00c..b010650 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -471,7 +471,7 @@
     if (kIsDebugBuild) {
       // Ensure the string is strongly interned. b/32995596
       if (object->IsString()) {
-        ObjPtr<mirror::String> str = reinterpret_cast<mirror::String*>(object.Ptr());
+        ObjPtr<mirror::String> str = ObjPtr<mirror::String>::DownCast(object);
         ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
         CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr);
       }
diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc
index 987c8e9..7290d63 100644
--- a/runtime/jni/jni_internal.cc
+++ b/runtime/jni/jni_internal.cc
@@ -2036,14 +2036,14 @@
         return nullptr;
       }
       ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-      array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
+      array_class = class_linker->FindArrayClass(soa.Self(), element_class);
       if (UNLIKELY(array_class == nullptr)) {
         return nullptr;
       }
     }
 
     // Allocate and initialize if necessary.
-    mirror::ObjectArray<mirror::Object>* result =
+    ObjPtr<mirror::ObjectArray<mirror::Object>> result =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
     if (result != nullptr && initial_element != nullptr) {
       ObjPtr<mirror::Object> initial_object = soa.Decode<mirror::Object>(initial_element);
@@ -2548,7 +2548,7 @@
       soa.Vm()->JniAbortF("NewPrimitiveArray", "negative array length: %d", length);
       return nullptr;
     }
-    ArtT* result = ArtT::Alloc(soa.Self(), length);
+    ObjPtr<ArtT> result = ArtT::Alloc(soa.Self(), length);
     return soa.AddLocalReference<JniT>(result);
   }
 
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 28df174..01a32a2 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -268,7 +268,7 @@
 
     // Then perform the actual boxing, and then set the reference.
     ObjPtr<mirror::Object> boxed = BoxPrimitive(type, src_value);
-    value->SetL(boxed.Ptr());
+    value->SetL(boxed);
     return true;
   } else {
     // The source type is a reference and the target type is a primitive, so we must unbox.
@@ -323,7 +323,7 @@
     // Note: As an optimization, non-moving collectors leave a stale reference value
     // in the references array even after the original vreg was overwritten to a non-reference.
     if (src_value == reinterpret_cast<uintptr_t>(o.Ptr())) {
-      callee_frame->SetVRegReference(dst_reg, o.Ptr());
+      callee_frame->SetVRegReference(dst_reg, o);
     } else {
       callee_frame->SetVReg(dst_reg, src_value);
     }
diff --git a/runtime/method_handles_test.cc b/runtime/method_handles_test.cc
index 0db9551..d123754 100644
--- a/runtime/method_handles_test.cc
+++ b/runtime/method_handles_test.cc
@@ -179,7 +179,7 @@
   StackHandleScope<3> hs(soa.Self());
   static const int32_t kInitialValue = 101;
   JValue value = JValue::FromPrimitive(kInitialValue);
-  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
   Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass());
   Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
   value.SetL(boxed_value.Get());
@@ -195,8 +195,7 @@
   ClassLinker* cl = Runtime::Current()->GetClassLinker();
   StackHandleScope<3> hs(soa.Self());
   JValue value = JValue::FromPrimitive(3.733e2);
-  Handle<mirror::Object> boxed_value =
-      hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value));
   Handle<mirror::Class> from = hs.NewHandle(boxed_value->GetClass());
   Handle<mirror::Class> to = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
   value.SetL(boxed_value.Get());
@@ -293,7 +292,7 @@
   StackHandleScope<3> hs(soa.Self());
   const int32_t kInitialValue = 101;
   JValue value = JValue::FromPrimitive(kInitialValue);
-  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
   Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
   Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('I'));
   value.SetL(boxed_value.Get());
@@ -308,7 +307,7 @@
   StackHandleScope<3> hs(soa.Self());
   static const int32_t kInitialValue = 101;
   JValue value = JValue::FromPrimitive(kInitialValue);
-  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
   Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
   Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('J'));
   value.SetL(boxed_value.Get());
@@ -352,7 +351,7 @@
   StackHandleScope<3> hs(soa.Self());
   static const int32_t kInitialValue = 101;
   JValue value = JValue::FromPrimitive(kInitialValue);
-  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimInt, value));
   Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Integer;"));
   Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('S'));
   value.SetL(boxed_value.Get());
@@ -368,8 +367,7 @@
   StackHandleScope<3> hs(soa.Self());
   static const double kInitialValue = 1e77;
   JValue value = JValue::FromPrimitive(kInitialValue);
-  Handle<mirror::Object> boxed_value =
-      hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value).Ptr());
+  Handle<mirror::Object> boxed_value = hs.NewHandle(BoxPrimitive(Primitive::kPrimDouble, value));
   Handle<mirror::Class> from = hs.NewHandle(cl->FindSystemClass(soa.Self(), "Ljava/lang/Number;"));
   Handle<mirror::Class> to = hs.NewHandle(cl->FindPrimitiveClass('F'));
   value.SetL(boxed_value.Get());
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index d2adcb4..2e39530 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -151,11 +151,11 @@
 };
 
 template <bool kIsInstrumented, bool kFillUsable>
-inline Array* Array::Alloc(Thread* self,
-                           ObjPtr<Class> array_class,
-                           int32_t component_count,
-                           size_t component_size_shift,
-                           gc::AllocatorType allocator_type) {
+inline ObjPtr<Array> Array::Alloc(Thread* self,
+                                  ObjPtr<Class> array_class,
+                                  int32_t component_count,
+                                  size_t component_size_shift,
+                                  gc::AllocatorType allocator_type) {
   DCHECK(allocator_type != gc::kAllocatorTypeLOS);
   DCHECK(array_class != nullptr);
   DCHECK(array_class->IsArrayClass());
@@ -175,19 +175,19 @@
   }
 #endif
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  Array* result;
+  ObjPtr<Array> result;
   if (!kFillUsable) {
     SetLengthVisitor visitor(component_count);
-    result = down_cast<Array*>(
+    result = ObjPtr<Array>::DownCast(MakeObjPtr(
         heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size,
-                                                              allocator_type, visitor));
+                                                              allocator_type, visitor)));
   } else {
     SetLengthToUsableSizeVisitor visitor(component_count,
                                          DataOffset(1U << component_size_shift).SizeValue(),
                                          component_size_shift);
-    result = down_cast<Array*>(
+    result = ObjPtr<Array>::DownCast(MakeObjPtr(
         heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, array_class, size,
-                                                              allocator_type, visitor));
+                                                              allocator_type, visitor)));
   }
   if (kIsDebugBuild && result != nullptr && Runtime::Current()->IsStarted()) {
     array_class = result->GetClass();  // In case the array class moved.
@@ -202,9 +202,9 @@
 }
 
 template<typename T>
-inline PrimitiveArray<T>* PrimitiveArray<T>::AllocateAndFill(Thread* self,
-                                                             const T* data,
-                                                             size_t length) {
+inline ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::AllocateAndFill(Thread* self,
+                                                                   const T* data,
+                                                                   size_t length) {
   StackHandleScope<1> hs(self);
   Handle<PrimitiveArray<T>> arr(hs.NewHandle(PrimitiveArray<T>::Alloc(self, length)));
   if (!arr.IsNull()) {
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 06ce0bb..66ec368 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -42,17 +42,18 @@
 // piece and work our way in.
 // Recursively create an array with multiple dimensions.  Elements may be
 // Objects or primitive types.
-static Array* RecursiveCreateMultiArray(Thread* self,
-                                        Handle<Class> array_class, int current_dimension,
-                                        Handle<mirror::IntArray> dimensions)
+static ObjPtr<Array> RecursiveCreateMultiArray(Thread* self,
+                                               Handle<Class> array_class,
+                                               int current_dimension,
+                                               Handle<mirror::IntArray> dimensions)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   int32_t array_length = dimensions->Get(current_dimension);
-  StackHandleScope<1> hs(self);
-  Handle<Array> new_array(
-      hs.NewHandle(
-          Array::Alloc<true>(self, array_class.Get(), array_length,
-                             array_class->GetComponentSizeShift(),
-                             Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> h_component_type(hs.NewHandle(array_class->GetComponentType()));
+  size_t component_size_shift = h_component_type->GetPrimitiveTypeSizeShift();
+  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
+  Handle<Array> new_array(hs.NewHandle(Array::Alloc<true>(
+      self, array_class.Get(), array_length, component_size_shift, allocator_type)));
   if (UNLIKELY(new_array == nullptr)) {
     CHECK(self->IsExceptionPending());
     return nullptr;
@@ -60,10 +61,8 @@
   if (current_dimension + 1 < dimensions->GetLength()) {
     // Create a new sub-array in every element of the array.
     for (int32_t i = 0; i < array_length; i++) {
-      StackHandleScope<1> hs2(self);
-      Handle<mirror::Class> h_component_type(hs2.NewHandle(array_class->GetComponentType()));
-      ObjPtr<Array> sub_array = RecursiveCreateMultiArray(self, h_component_type,
-                                                   current_dimension + 1, dimensions);
+      ObjPtr<Array> sub_array =
+          RecursiveCreateMultiArray(self, h_component_type, current_dimension + 1, dimensions);
       if (UNLIKELY(sub_array == nullptr)) {
         CHECK(self->IsExceptionPending());
         return nullptr;
@@ -75,8 +74,9 @@
   return new_array.Get();
 }
 
-Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class,
-                               Handle<IntArray> dimensions) {
+ObjPtr<Array> Array::CreateMultiArray(Thread* self,
+                                      Handle<Class> element_class,
+                                      Handle<IntArray> dimensions) {
   // Verify dimensions.
   //
   // The caller is responsible for verifying that "dimArray" is non-null
@@ -95,17 +95,15 @@
 
   // Find/generate the array class.
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  ObjPtr<mirror::Class>  element_class_ptr = element_class.Get();
   StackHandleScope<1> hs(self);
   MutableHandle<mirror::Class> array_class(
-      hs.NewHandle(class_linker->FindArrayClass(self, &element_class_ptr)));
+      hs.NewHandle(class_linker->FindArrayClass(self, element_class.Get())));
   if (UNLIKELY(array_class == nullptr)) {
     CHECK(self->IsExceptionPending());
     return nullptr;
   }
   for (int32_t i = 1; i < dimensions->GetLength(); ++i) {
-    ObjPtr<mirror::Class> array_class_ptr = array_class.Get();
-    array_class.Assign(class_linker->FindArrayClass(self, &array_class_ptr));
+    array_class.Assign(class_linker->FindArrayClass(self, array_class.Get()));
     if (UNLIKELY(array_class == nullptr)) {
       CHECK(self->IsExceptionPending());
       return nullptr;
@@ -120,13 +118,14 @@
 }
 
 template<typename T>
-PrimitiveArray<T>* PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
-  Array* raw_array = Array::Alloc<true>(self,
-                                        GetClassRoot<PrimitiveArray<T>>(),
-                                        length,
-                                        ComponentSizeShiftWidth(sizeof(T)),
-                                        Runtime::Current()->GetHeap()->GetCurrentAllocator());
-  return down_cast<PrimitiveArray<T>*>(raw_array);
+ObjPtr<PrimitiveArray<T>> PrimitiveArray<T>::Alloc(Thread* self, size_t length) {
+  gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
+  ObjPtr<Array> raw_array = Array::Alloc<true>(self,
+                                               GetClassRoot<PrimitiveArray<T>>(),
+                                               length,
+                                               ComponentSizeShiftWidth(sizeof(T)),
+                                               allocator_type);
+  return ObjPtr<PrimitiveArray<T>>::DownCast(raw_array);
 }
 
 void Array::ThrowArrayIndexOutOfBoundsException(int32_t index) {
@@ -137,7 +136,7 @@
   art::ThrowArrayStoreException(object->GetClass(), this->GetClass());
 }
 
-Array* Array::CopyOf(Thread* self, int32_t new_length) {
+ObjPtr<Array> Array::CopyOf(Thread* self, int32_t new_length) {
   CHECK(GetClass()->GetComponentType()->IsPrimitive()) << "Will miss write barriers";
   DCHECK_GE(new_length, 0);
   // We may get copied by a compacting GC.
@@ -148,7 +147,8 @@
       heap->GetCurrentNonMovingAllocator();
   const auto component_size = GetClass()->GetComponentSize();
   const auto component_shift = GetClass()->GetComponentSizeShift();
-  ObjPtr<Array> new_array = Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type);
+  ObjPtr<Array> new_array =
+      Alloc<true>(self, GetClass(), new_length, component_shift, allocator_type);
   if (LIKELY(new_array != nullptr)) {
     memcpy(new_array->GetRawData(component_size, 0),
            h_this->GetRawData(component_size, 0),
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index aeaaf673..8bdd561 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -37,17 +37,17 @@
   // least component_count size, however, if there's usable space at the end of the allocation the
   // array will fill it.
   template <bool kIsInstrumented, bool kFillUsable = false>
-  ALWAYS_INLINE static Array* Alloc(Thread* self,
-                                    ObjPtr<Class> array_class,
-                                    int32_t component_count,
-                                    size_t component_size_shift,
-                                    gc::AllocatorType allocator_type)
+  ALWAYS_INLINE static ObjPtr<Array> Alloc(Thread* self,
+                                           ObjPtr<Class> array_class,
+                                           int32_t component_count,
+                                           size_t component_size_shift,
+                                           gc::AllocatorType allocator_type)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
-  static Array* CreateMultiArray(Thread* self,
-                                 Handle<Class> element_class,
-                                 Handle<IntArray> dimensions)
+  static ObjPtr<Array> CreateMultiArray(Thread* self,
+                                        Handle<Class> element_class,
+                                        Handle<IntArray> dimensions)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
@@ -90,7 +90,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ALWAYS_INLINE bool CheckIsValidIndex(int32_t index) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  Array* CopyOf(Thread* self, int32_t new_length) REQUIRES_SHARED(Locks::mutator_lock_)
+  ObjPtr<Array> CopyOf(Thread* self, int32_t new_length) REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
  protected:
@@ -114,10 +114,10 @@
  public:
   typedef T ElementType;
 
-  static PrimitiveArray<T>* Alloc(Thread* self, size_t length)
+  static ObjPtr<PrimitiveArray<T>> Alloc(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
-  static PrimitiveArray<T>* AllocateAndFill(Thread* self, const T* data, size_t length)
+  static ObjPtr<PrimitiveArray<T>> AllocateAndFill(Thread* self, const T* data, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
 
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 5328ad9..fffd7f3 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -294,7 +294,7 @@
   return GetFieldObject<PointerArray>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_));
 }
 
-inline void Class::SetVTable(PointerArray* new_vtable) {
+inline void Class::SetVTable(ObjPtr<PointerArray> new_vtable) {
   SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable);
 }
 
@@ -486,7 +486,7 @@
     if (UNLIKELY(!this->CanAccess(dex_access_to))) {
       if (throw_on_failure) {
         ThrowIllegalAccessErrorClassForMethodDispatch(this,
-                                                      dex_access_to.Ptr(),
+                                                      dex_access_to,
                                                       method,
                                                       throw_invoke_type);
       }
@@ -797,7 +797,7 @@
       obj = nullptr;
     }
   }
-  return obj.Ptr();
+  return obj;
 }
 
 inline ObjPtr<Object> Class::AllocObject(Thread* self) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 31a83f8..44b0c2b 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -419,7 +419,7 @@
 }
 
 bool Class::IsThrowableClass() {
-  return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this);
+  return GetClassRoot<mirror::Throwable>()->IsAssignableFrom(this);
 }
 
 void Class::SetClassLoader(ObjPtr<ClassLoader> new_class_loader) {
@@ -1269,7 +1269,7 @@
   for (auto& m : h_klass->GetDeclaredVirtualMethods(kPointerSize)) {
     auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize);
     // May cause thread suspension.
-    ObjPtr<String> np_name = np_method->GetNameAsString(self);
+    ObjPtr<String> np_name = np_method->ResolveNameString();
     if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) {
       if (UNLIKELY(self->IsExceptionPending())) {
         return nullptr;
@@ -1291,7 +1291,7 @@
       }
       auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize);
       // May cause thread suspension.
-      ObjPtr<String> np_name = np_method->GetNameAsString(self);
+      ObjPtr<String> np_name = np_method->ResolveNameString();
       if (np_name == nullptr) {
         self->AssertPendingException();
         return nullptr;
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 6feaa9c..c3e167c 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -781,7 +781,7 @@
 
   ALWAYS_INLINE PointerArray* GetVTableDuringLinking() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void SetVTable(PointerArray* new_vtable) REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetVTable(ObjPtr<PointerArray> new_vtable) REQUIRES_SHARED(Locks::mutator_lock_);
 
   static MemberOffset VTableOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Class, vtable_);
diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc
index 7214620..44bf989 100644
--- a/runtime/mirror/class_ext.cc
+++ b/runtime/mirror/class_ext.cc
@@ -43,8 +43,8 @@
   auto obsolete_dex_cache_off = OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_dex_caches_);
   auto obsolete_methods_off = OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_methods_);
   DCHECK(!Runtime::Current()->IsActiveTransaction());
-  SetFieldObject<false>(obsolete_dex_cache_off, dex_caches.Ptr());
-  SetFieldObject<false>(obsolete_methods_off, methods.Ptr());
+  SetFieldObject<false>(obsolete_dex_cache_off, dex_caches);
+  SetFieldObject<false>(obsolete_methods_off, methods);
 }
 
 // We really need to be careful how we update this. If we ever in the future make it so that
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index cd822c2..ee4f53b 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -114,10 +114,6 @@
   Monitor::NotifyAll(self, this);
 }
 
-inline void Object::Wait(Thread* self) {
-  Monitor::Wait(self, this, 0, 0, true, kWaiting);
-}
-
 inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) {
   Monitor::Wait(self, this, ms, ns, true, kTimedWaiting);
 }
@@ -776,7 +772,7 @@
     } else {
       obj = GetFieldObject<Object>(field_offset);
     }
-    Runtime::Current()->RecordWriteFieldReference(this, field_offset, obj.Ptr(), true);
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset, obj, true);
   }
   if (kVerifyFlags & kVerifyThis) {
     VerifyObject(this);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 8584b8a..a89d632 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -176,7 +176,6 @@
       UNLOCK_FUNCTION();
   void Notify(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
   void NotifyAll(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
-  void Wait(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
   void Wait(Thread* self, int64_t timeout, int32_t nanos) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index 086d2f4..ed3c567 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -37,14 +37,15 @@
 namespace mirror {
 
 template<class T>
-inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self,
-                                             ObjPtr<Class> object_array_class,
-                                             int32_t length, gc::AllocatorType allocator_type) {
-  Array* array = Array::Alloc<true>(self,
-                                    object_array_class.Ptr(),
-                                    length,
-                                    ComponentSizeShiftWidth(kHeapReferenceSize),
-                                    allocator_type);
+inline ObjPtr<ObjectArray<T>> ObjectArray<T>::Alloc(Thread* self,
+                                                    ObjPtr<Class> object_array_class,
+                                                    int32_t length,
+                                                    gc::AllocatorType allocator_type) {
+  ObjPtr<Array> array = Array::Alloc<true>(self,
+                                           object_array_class,
+                                           length,
+                                           ComponentSizeShiftWidth(kHeapReferenceSize),
+                                           allocator_type);
   if (UNLIKELY(array == nullptr)) {
     return nullptr;
   }
@@ -54,9 +55,9 @@
 }
 
 template<class T>
-inline ObjectArray<T>* ObjectArray<T>::Alloc(Thread* self,
-                                             ObjPtr<Class> object_array_class,
-                                             int32_t length) {
+inline ObjPtr<ObjectArray<T>> ObjectArray<T>::Alloc(Thread* self,
+                                                    ObjPtr<Class> object_array_class,
+                                                    int32_t length) {
   return Alloc(self,
                object_array_class,
                length,
@@ -346,7 +347,7 @@
 }
 
 template<class T>
-inline ObjectArray<T>* ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) {
+inline ObjPtr<ObjectArray<T>> ObjectArray<T>::CopyOf(Thread* self, int32_t new_length) {
   DCHECK_GE(new_length, 0);
   // We may get copied by a compacting GC.
   StackHandleScope<1> hs(self);
@@ -354,7 +355,7 @@
   gc::Heap* heap = Runtime::Current()->GetHeap();
   gc::AllocatorType allocator_type = heap->IsMovableObject(this) ? heap->GetCurrentAllocator() :
       heap->GetCurrentNonMovingAllocator();
-  ObjectArray<T>* new_array = Alloc(self, GetClass(), new_length, allocator_type);
+  ObjPtr<ObjectArray<T>> new_array = Alloc(self, GetClass(), new_length, allocator_type);
   if (LIKELY(new_array != nullptr)) {
     new_array->AssignableMemcpy(0, h_this.Get(), 0, std::min(h_this->GetLength(), new_length));
   }
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index b7a9561..6506f6e 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -31,15 +31,15 @@
     return Array::ClassSize(pointer_size);
   }
 
-  static ObjectArray<T>* Alloc(Thread* self,
-                               ObjPtr<Class> object_array_class,
-                               int32_t length,
-                               gc::AllocatorType allocator_type)
+  static ObjPtr<ObjectArray<T>> Alloc(Thread* self,
+                                      ObjPtr<Class> object_array_class,
+                                      int32_t length,
+                                      gc::AllocatorType allocator_type)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
-  static ObjectArray<T>* Alloc(Thread* self,
-                               ObjPtr<Class> object_array_class,
-                               int32_t length)
+  static ObjPtr<ObjectArray<T>> Alloc(Thread* self,
+                                      ObjPtr<Class> object_array_class,
+                                      int32_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
@@ -99,7 +99,7 @@
                                 bool throw_exception)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ObjectArray<T>* CopyOf(Thread* self, int32_t new_length)
+  ObjPtr<ObjectArray<T>> CopyOf(Thread* self, int32_t new_length)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Roles::uninterruptible_);
 
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 8b7a1b6..0b615a6 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -76,7 +76,7 @@
   }
 
   template <class T>
-  mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
+  ObjPtr<mirror::ObjectArray<T>> AllocObjectArray(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return mirror::ObjectArray<T>::Alloc(
         self, GetClassRoot(ClassRoot::kObjectArrayClass, class_linker_), length);
@@ -206,7 +206,8 @@
   ScopedObjectAccess soa(Thread::Current());
   typedef typename ArrayT::ElementType T;
 
-  ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2));
   EXPECT_EQ(2, a->GetLength());
   EXPECT_EQ(0, a->Get(0));
   EXPECT_EQ(0, a->Get(1));
@@ -217,7 +218,6 @@
   EXPECT_EQ(T(123), a->Get(0));
   EXPECT_EQ(T(321), a->Get(1));
 
-  StackHandleScope<1> hs(soa.Self());
   Handle<Class> aioobe = hs.NewHandle(
       cl->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;"));
 
@@ -256,7 +256,8 @@
   ScopedObjectAccess soa(Thread::Current());
   typedef typename ArrayT::ElementType T;
 
-  ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2));
   EXPECT_EQ(2, a->GetLength());
   EXPECT_DOUBLE_EQ(0, a->Get(0));
   EXPECT_DOUBLE_EQ(0, a->Get(1));
@@ -267,7 +268,6 @@
   EXPECT_DOUBLE_EQ(T(123), a->Get(0));
   EXPECT_DOUBLE_EQ(T(321), a->Get(1));
 
-  StackHandleScope<1> hs(soa.Self());
   Handle<Class> aioobe = hs.NewHandle(
       class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;"));
 
@@ -287,7 +287,8 @@
   ScopedObjectAccess soa(Thread::Current());
   typedef typename ArrayT::ElementType T;
 
-  ArrayT* a = ArrayT::Alloc(soa.Self(), 2);
+  StackHandleScope<2> hs(soa.Self());
+  Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2));
   EXPECT_FLOAT_EQ(2, a->GetLength());
   EXPECT_FLOAT_EQ(0, a->Get(0));
   EXPECT_FLOAT_EQ(0, a->Get(1));
@@ -298,7 +299,6 @@
   EXPECT_FLOAT_EQ(T(123), a->Get(0));
   EXPECT_FLOAT_EQ(T(321), a->Get(1));
 
-  StackHandleScope<1> hs(soa.Self());
   Handle<Class> aioobe = hs.NewHandle(
       class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/ArrayIndexOutOfBoundsException;"));
 
@@ -317,16 +317,17 @@
 TEST_F(ObjectTest, CreateMultiArray) {
   ScopedObjectAccess soa(Thread::Current());
 
-  StackHandleScope<2> hs(soa.Self());
-  Handle<Class> c(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I")));
+  StackHandleScope<4> hs(soa.Self());
+  Handle<Class> int_class(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I")));
+  Handle<Class> int_array_class = hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "[I"));
   MutableHandle<IntArray> dims(hs.NewHandle(IntArray::Alloc(soa.Self(), 1)));
   dims->Set<false>(0, 1);
-  Array* multi = Array::CreateMultiArray(soa.Self(), c, dims);
-  EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I"));
+  MutableHandle<Array> multi = hs.NewHandle(Array::CreateMultiArray(soa.Self(), int_class, dims));
+  EXPECT_OBJ_PTR_EQ(int_array_class.Get(), multi->GetClass());
   EXPECT_EQ(1, multi->GetLength());
 
   dims->Set<false>(0, -1);
-  multi = Array::CreateMultiArray(soa.Self(), c, dims);
+  multi.Assign(Array::CreateMultiArray(soa.Self(), int_class, dims));
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
   EXPECT_EQ(mirror::Class::PrettyDescriptor(soa.Self()->GetException()->GetClass()),
             "java.lang.NegativeArraySizeException");
@@ -337,12 +338,12 @@
     for (int j = 0; j < 20; ++j) {
       dims->Set<false>(0, i);
       dims->Set<false>(1, j);
-      multi = Array::CreateMultiArray(soa.Self(), c, dims);
+      multi.Assign(Array::CreateMultiArray(soa.Self(), int_class, dims));
       EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[[I"));
       EXPECT_EQ(i, multi->GetLength());
       for (int k = 0; k < i; ++k) {
-        Array* outer = multi->AsObjectArray<Array>()->Get(k);
-        EXPECT_TRUE(outer->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I"));
+        ObjPtr<Array> outer = multi->AsObjectArray<Array>()->Get(k);
+        EXPECT_OBJ_PTR_EQ(int_array_class.Get(), outer->GetClass());
         EXPECT_EQ(j, outer->GetLength());
       }
     }
@@ -817,7 +818,7 @@
 
   ObjPtr<mirror::Class> c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;");
   ASSERT_TRUE(c != nullptr);
-  mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0);
+  ObjPtr<mirror::Object> o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0);
   EXPECT_EQ("java.lang.String[]", mirror::Object::PrettyTypeOf(o));
   EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Object::PrettyTypeOf(o->GetClass()));
 }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 6c82019..3227c69 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -32,6 +32,7 @@
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "debugger.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_types.h"
 #include "gc/accounting/card_table-inl.h"
@@ -111,7 +112,7 @@
   }
   Runtime* runtime = Runtime::Current();
   ObjPtr<mirror::Class> array_class =
-      runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
+      runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class);
   if (UNLIKELY(array_class == nullptr)) {
     return nullptr;
   }
@@ -138,7 +139,7 @@
   }
   Runtime* runtime = Runtime::Current();
   ObjPtr<mirror::Class> array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
-                                                                                &element_class);
+                                                                                element_class);
   if (UNLIKELY(array_class == nullptr)) {
     return nullptr;
   }
@@ -573,30 +574,12 @@
     }
 
     if (kPreloadDexCachesFieldsAndMethods) {
-      for (size_t class_def_index = 0;
-           class_def_index < dex_file->NumClassDefs();
-           class_def_index++) {
-        const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
-        const uint8_t* class_data = dex_file->GetClassData(class_def);
-        if (class_data == nullptr) {
-          continue;
+      for (ClassAccessor accessor : dex_file->GetClasses()) {
+        for (const ClassAccessor::Field& field : accessor.GetFields()) {
+          PreloadDexCachesResolveField(dex_cache, field.GetIndex(), field.IsStatic());
         }
-        ClassDataItemIterator it(*dex_file, class_data);
-        for (; it.HasNextStaticField(); it.Next()) {
-          uint32_t field_idx = it.GetMemberIndex();
-          PreloadDexCachesResolveField(dex_cache, field_idx, true);
-        }
-        for (; it.HasNextInstanceField(); it.Next()) {
-          uint32_t field_idx = it.GetMemberIndex();
-          PreloadDexCachesResolveField(dex_cache, field_idx, false);
-        }
-        for (; it.HasNextDirectMethod(); it.Next()) {
-          uint32_t method_idx = it.GetMemberIndex();
-          PreloadDexCachesResolveMethod(dex_cache, method_idx);
-        }
-        for (; it.HasNextVirtualMethod(); it.Next()) {
-          uint32_t method_idx = it.GetMemberIndex();
-          PreloadDexCachesResolveMethod(dex_cache, method_idx);
+        for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+          PreloadDexCachesResolveMethod(dex_cache, method.GetIndex());
         }
       }
     }
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 38c65f5..5b47eac 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -100,7 +100,7 @@
   }
 
   void AddClass(ObjPtr<mirror::Class> klass) REQUIRES(Locks::mutator_lock_) {
-    class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass.Ptr()));
+    class_set_.insert(self_->GetJniEnv()->AddLocalReference<jclass>(klass));
   }
 
   const std::unordered_set<jclass>& GetClasses() const {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index c6bdfa1..82e54e2 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -646,8 +646,8 @@
         soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
     ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
-                                                   annotation_array_class.Ptr(),
-                                                   0);
+                                                   annotation_array_class,
+                                                   /* length */ 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass));
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index 208ccf6..48540f8 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -41,11 +41,6 @@
   soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self());
 }
 
-static void Object_wait(JNIEnv* env, jobject java_this) {
-  ScopedFastNativeObjectAccess soa(env);
-  soa.Decode<mirror::Object>(java_this)->Wait(soa.Self());
-}
-
 static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) {
   ScopedFastNativeObjectAccess soa(env);
   soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns);
@@ -61,7 +56,6 @@
   FAST_NATIVE_METHOD(Object, internalClone, "()Ljava/lang/Object;"),
   FAST_NATIVE_METHOD(Object, notify, "()V"),
   FAST_NATIVE_METHOD(Object, notifyAll, "()V"),
-  OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "()V", wait),
   OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "(JI)V", waitJI),
   FAST_NATIVE_METHOD(Object, identityHashCodeNative, "(Ljava/lang/Object;)I"),
 };
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index a37a76f..13871f7 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -119,7 +119,7 @@
     return JNI_FALSE;
   }
   Thread* thread = soa.Self();
-  return thread->HoldsLock(object.Ptr());
+  return thread->HoldsLock(object);
 }
 
 static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 42c7ad5..1ad233a 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -86,7 +86,7 @@
   }
   // If class is erroneous, throw the earlier failure, wrapped in certain cases. See b/28787733.
   if (c != nullptr && c->IsErroneous()) {
-    cl->ThrowEarlierClassFailure(c.Ptr());
+    cl->ThrowEarlierClassFailure(c);
     Thread* self = soa.Self();
     ObjPtr<mirror::Class> iae_class =
         self->DecodeJObject(WellKnownClasses::java_lang_IllegalAccessError)->AsClass();
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 8bcda10..452a66d 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -44,9 +44,8 @@
             Primitive::kPrimInt);
   Handle<mirror::IntArray> dimensions_array(
       hs.NewHandle(ObjPtr<mirror::IntArray>::DownCast(dimensions_obj)));
-  mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(),
-                                                             element_class,
-                                                             dimensions_array);
+  ObjPtr<mirror::Array> new_array =
+      mirror::Array::CreateMultiArray(soa.Self(), element_class, dimensions_array);
   return soa.AddLocalReference<jobject>(new_array);
 }
 
@@ -57,16 +56,16 @@
     ThrowNegativeArraySizeException(length);
     return nullptr;
   }
-  ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
   Runtime* runtime = Runtime::Current();
   ClassLinker* class_linker = runtime->GetClassLinker();
-  ObjPtr<mirror::Class> array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
+  ObjPtr<mirror::Class> array_class =
+      class_linker->FindArrayClass(soa.Self(), soa.Decode<mirror::Class>(javaElementClass));
   if (UNLIKELY(array_class == nullptr)) {
     CHECK(soa.Self()->IsExceptionPending());
     return nullptr;
   }
   DCHECK(array_class->IsObjectArrayClass());
-  ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object*>::Alloc(
+  ObjPtr<mirror::Array> new_array = mirror::ObjectArray<mirror::Object>::Alloc(
       soa.Self(),
       array_class,
       length,
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index a40cb9b..a10db91 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -320,7 +320,7 @@
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
-  return soa.AddLocalReference<jstring>(method->GetNameAsString(soa.Self()));
+  return soa.AddLocalReference<jstring>(method->ResolveNameString());
 }
 
 static jclass Executable_getMethodReturnTypeInternal(JNIEnv* env, jobject javaMethod) {
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 2559984..895b2f9 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -464,8 +464,7 @@
 static jstring Field_getNameInternal(JNIEnv* env, jobject javaField) {
   ScopedFastNativeObjectAccess soa(env);
   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
-  return soa.AddLocalReference<jstring>(
-      field->GetStringName(soa.Self(), true /* resolve */));
+  return soa.AddLocalReference<jstring>(field->ResolveNameString());
 }
 
 static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
@@ -476,7 +475,7 @@
     ObjPtr<mirror::Class> annotation_array_class =
         soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
     ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Ptr(), 0);
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForField(field));
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 34455fe..87fda6b 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -69,7 +69,7 @@
       // Return an empty array instead of a null pointer
       ObjPtr<mirror::Class> class_array_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>();
       DCHECK(class_array_class != nullptr);
-      mirror::ObjectArray<mirror::Class>* empty_array =
+      ObjPtr<mirror::ObjectArray<mirror::Class>> empty_array =
           mirror::ObjectArray<mirror::Class>::Alloc(soa.Self(), class_array_class, 0);
       return soa.AddLocalReference<jobjectArray>(empty_array);
     } else {
diff --git a/runtime/oat.h b/runtime/oat.h
index e7e5848..72eb27d 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  // Last oat version changed reason: Rewrite dex register map encoding.
-  static constexpr uint8_t kOatVersion[] = { '1', '4', '6', '\0' };
+  // Last oat version changed reason: Rewrite TypeLookupTable.
+  static constexpr uint8_t kOatVersion[] = { '1', '4', '7', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index ffbc26c..2b05b0e 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1687,6 +1687,7 @@
       type_bss_mapping_(type_bss_mapping_data),
       string_bss_mapping_(string_bss_mapping_data),
       oat_class_offsets_pointer_(oat_class_offsets_pointer),
+      lookup_table_(),
       dex_layout_sections_(dex_layout_sections) {
   // Initialize TypeLookupTable.
   if (lookup_table_data_ != nullptr) {
@@ -1706,7 +1707,7 @@
   }
 }
 
-OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table)
+OatFile::OatDexFile::OatDexFile(TypeLookupTable&& lookup_table)
     : lookup_table_(std::move(lookup_table)) {}
 
 OatFile::OatDexFile::~OatDexFile() {}
@@ -1783,9 +1784,9 @@
   DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash);
   bool used_lookup_table = false;
   const DexFile::ClassDef* lookup_table_classdef = nullptr;
-  if (LIKELY((oat_dex_file != nullptr) && (oat_dex_file->GetTypeLookupTable() != nullptr))) {
+  if (LIKELY((oat_dex_file != nullptr) && oat_dex_file->GetTypeLookupTable().Valid())) {
     used_lookup_table = true;
-    const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable()->Lookup(descriptor, hash);
+    const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable().Lookup(descriptor, hash);
     lookup_table_classdef = (class_def_idx != dex::kDexNoIndex)
         ? &dex_file.GetClassDef(class_def_idx)
         : nullptr;
@@ -1796,6 +1797,7 @@
   // Fast path for rare no class defs case.
   const uint32_t num_class_defs = dex_file.NumClassDefs();
   if (num_class_defs == 0) {
+    DCHECK(!used_lookup_table);
     return nullptr;
   }
   const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 8e18cee..d72b6a8 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -514,14 +514,14 @@
   // Madvise the dex file based on the state we are moving to.
   static void MadviseDexFile(const DexFile& dex_file, MadviseState state);
 
-  TypeLookupTable* GetTypeLookupTable() const {
-    return lookup_table_.get();
+  const TypeLookupTable& GetTypeLookupTable() const {
+    return lookup_table_;
   }
 
   ~OatDexFile();
 
   // Create only with a type lookup table, used by the compiler to speed up compilation.
-  explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);
+  explicit OatDexFile(TypeLookupTable&& lookup_table);
 
   // Return the dex layout sections.
   const DexLayoutSections* GetDexLayoutSections() const {
@@ -553,7 +553,7 @@
   const IndexBssMapping* const type_bss_mapping_ = nullptr;
   const IndexBssMapping* const string_bss_mapping_ = nullptr;
   const uint32_t* const oat_class_offsets_pointer_ = 0u;
-  mutable std::unique_ptr<TypeLookupTable> lookup_table_;
+  TypeLookupTable lookup_table_;
   const DexLayoutSections* const dex_layout_sections_ = nullptr;
 
   friend class OatFile;
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index 06ea384..1d54d21 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -106,7 +106,7 @@
   }
 
   // Add a second object 10 times and check dumping is sane.
-  mirror::Object* o2 = mirror::ShortArray::Alloc(soa.Self(), 0);
+  ObjPtr<mirror::Object> o2 = mirror::ShortArray::Alloc(soa.Self(), 0);
   for (size_t i = 0; i < 10; ++i) {
     rt.Add(o2);
     EXPECT_EQ(i + 2, rt.Size());
@@ -276,23 +276,26 @@
   ReferenceTable rt("test", 0, 20);
 
   {
-    mirror::Object* s1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello");
-    mirror::Object* s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world");
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::String> s1 =
+        hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello"));
+    ObjPtr<mirror::String> s2 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "world");
 
     // 3 copies of s1, 2 copies of s2, interleaved.
     for (size_t i = 0; i != 2; ++i) {
-      rt.Add(s1);
+      rt.Add(s1.Get());
       rt.Add(s2);
     }
-    rt.Add(s1);
+    rt.Add(s1.Get());
   }
 
   {
-    // Differently sized byte arrays. Should be sorted by identical (non-unique cound).
-    mirror::Object* b1_1 = mirror::ByteArray::Alloc(soa.Self(), 1);
-    rt.Add(b1_1);
+    // Differently sized byte arrays. Should be sorted by identical (non-unique count).
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ByteArray> b1_1 = hs.NewHandle(mirror::ByteArray::Alloc(soa.Self(), 1));
+    rt.Add(b1_1.Get());
     rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2));
-    rt.Add(b1_1);
+    rt.Add(b1_1.Get());
     rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2));
     rt.Add(mirror::ByteArray::Alloc(soa.Self(), 1));
     rt.Add(mirror::ByteArray::Alloc(soa.Self(), 2));
diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h
index 26fb021..9fe4bca 100644
--- a/runtime/reflection-inl.h
+++ b/runtime/reflection-inl.h
@@ -121,7 +121,7 @@
   if (UNLIKELY(o == nullptr)) {
     ThrowNullPointerException("null receiver");
     return false;
-  } else if (UNLIKELY(!o->InstanceOf(c.Ptr()))) {
+  } else if (UNLIKELY(!o->InstanceOf(c))) {
     InvalidReceiverError(o, c);
     return false;
   }
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 66eba1e..6aeedd4 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -243,7 +243,7 @@
         // we've seen cases where it's not b/34440020.
         ObjPtr<mirror::Class> dst_class(
             m->ResolveClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_));
-        if (dst_class.Ptr() == nullptr) {
+        if (dst_class == nullptr) {
           CHECK(self->IsExceptionPending());
           return false;
         }
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0d9d16c..1e327fc 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1090,6 +1090,17 @@
   sentinel_ = GcRoot<mirror::Object>(sentinel);
 }
 
+static inline void InitPreAllocatedException(Thread* self,
+                                             GcRoot<mirror::Throwable>* exception,
+                                             const char* exception_class_descriptor,
+                                             const char* msg)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK_EQ(self, Thread::Current());
+  self->ThrowNewException(exception_class_descriptor, msg);
+  *exception = GcRoot<mirror::Throwable>(self->GetException());
+  self->ClearException();
+}
+
 bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
   // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
   // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.
@@ -1505,34 +1516,54 @@
   // TODO: move this to just be an Trace::Start argument
   Trace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock));
 
-  // Pre-allocate an OutOfMemoryError for the case when we fail to
-  // allocate the exception to be thrown.
-  InitPreAllocatedException(self,
-                            &Runtime::pre_allocated_OutOfMemoryError_when_throwing_exception_,
-                            "Ljava/lang/OutOfMemoryError;",
-                            "OutOfMemoryError thrown while trying to throw an exception; "
-                            "no stack trace available");
-  // Pre-allocate an OutOfMemoryError for the double-OOME case.
-  InitPreAllocatedException(self,
-                            &Runtime::pre_allocated_OutOfMemoryError_when_throwing_oome_,
-                            "Ljava/lang/OutOfMemoryError;",
-                            "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
-                            "no stack trace available");
-  // Pre-allocate an OutOfMemoryError for the case when we fail to
-  // allocate while handling a stack overflow.
-  InitPreAllocatedException(self,
-                            &Runtime::pre_allocated_OutOfMemoryError_when_handling_stack_overflow_,
-                            "Ljava/lang/OutOfMemoryError;",
-                            "OutOfMemoryError thrown while trying to handle a stack overflow; "
-                            "no stack trace available");
+  if (GetHeap()->HasBootImageSpace()) {
+    const ImageHeader& image_header = GetHeap()->GetBootImageSpaces()[0]->GetImageHeader();
+    pre_allocated_OutOfMemoryError_when_throwing_exception_ = GcRoot<mirror::Throwable>(
+        image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingException)->AsThrowable());
+    DCHECK(pre_allocated_OutOfMemoryError_when_throwing_exception_.Read()->GetClass()
+               ->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
+    pre_allocated_OutOfMemoryError_when_throwing_oome_ = GcRoot<mirror::Throwable>(
+        image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingOome)->AsThrowable());
+    DCHECK(pre_allocated_OutOfMemoryError_when_throwing_oome_.Read()->GetClass()
+               ->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
+    pre_allocated_OutOfMemoryError_when_handling_stack_overflow_ = GcRoot<mirror::Throwable>(
+        image_header.GetImageRoot(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable());
+    DCHECK(pre_allocated_OutOfMemoryError_when_handling_stack_overflow_.Read()->GetClass()
+               ->DescriptorEquals("Ljava/lang/OutOfMemoryError;"));
+    pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(
+        image_header.GetImageRoot(ImageHeader::kNoClassDefFoundError)->AsThrowable());
+    DCHECK(pre_allocated_NoClassDefFoundError_.Read()->GetClass()
+               ->DescriptorEquals("Ljava/lang/NoClassDefFoundError;"));
+  } else {
+    // Pre-allocate an OutOfMemoryError for the case when we fail to
+    // allocate the exception to be thrown.
+    InitPreAllocatedException(self,
+                              &pre_allocated_OutOfMemoryError_when_throwing_exception_,
+                              "Ljava/lang/OutOfMemoryError;",
+                              "OutOfMemoryError thrown while trying to throw an exception; "
+                              "no stack trace available");
+    // Pre-allocate an OutOfMemoryError for the double-OOME case.
+    InitPreAllocatedException(self,
+                              &pre_allocated_OutOfMemoryError_when_throwing_oome_,
+                              "Ljava/lang/OutOfMemoryError;",
+                              "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
+                              "no stack trace available");
+    // Pre-allocate an OutOfMemoryError for the case when we fail to
+    // allocate while handling a stack overflow.
+    InitPreAllocatedException(self,
+                              &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_,
+                              "Ljava/lang/OutOfMemoryError;",
+                              "OutOfMemoryError thrown while trying to handle a stack overflow; "
+                              "no stack trace available");
 
-  // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
-  // ahead of checking the application's class loader.
-  InitPreAllocatedException(self,
-                            &Runtime::pre_allocated_NoClassDefFoundError_,
-                            "Ljava/lang/NoClassDefFoundError;",
-                            "Class not found using the boot class loader; "
-                            "no stack trace available");
+    // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
+    // ahead of checking the application's class loader.
+    InitPreAllocatedException(self,
+                              &pre_allocated_NoClassDefFoundError_,
+                              "Ljava/lang/NoClassDefFoundError;",
+                              "Class not found using the boot class loader; "
+                              "no stack trace available");
+  }
 
   // Runtime initialization is largely done now.
   // We load plugins first since that can modify the runtime state slightly.
@@ -1682,16 +1713,6 @@
   }
 }
 
-void Runtime::InitPreAllocatedException(Thread* self,
-                                        GcRoot<mirror::Throwable> Runtime::* exception,
-                                        const char* exception_class_descriptor,
-                                        const char* msg) {
-  DCHECK_EQ(self, Thread::Current());
-  self->ThrowNewException(exception_class_descriptor, msg);
-  this->*exception = GcRoot<mirror::Throwable>(self->GetException());
-  self->ClearException();
-}
-
 void Runtime::InitNativeMethods() {
   VLOG(startup) << "Runtime::InitNativeMethods entering";
   Thread* self = Thread::Current();
@@ -2048,9 +2069,10 @@
       auto* image_space = space->AsImageSpace();
       const auto& image_header = image_space->GetImageHeader();
       for (int32_t i = 0, size = image_header.GetImageRoots()->GetLength(); i != size; ++i) {
-        auto* obj = image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i));
+        mirror::Object* obj =
+            image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i)).Ptr();
         if (obj != nullptr) {
-          auto* after_obj = obj;
+          mirror::Object* after_obj = obj;
           visitor->VisitRoot(&after_obj, RootInfo(kRootStickyClass));
           CHECK_EQ(after_obj, obj);
         }
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 10f72e7..d85490c 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -774,11 +774,6 @@
 
   bool Init(RuntimeArgumentMap&& runtime_options)
       SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_);
-  void InitPreAllocatedException(Thread* self,
-                                 GcRoot<mirror::Throwable> Runtime::* exception,
-                                 const char* exception_class_descriptor,
-                                 const char* msg)
-      REQUIRES_SHARED(Locks::mutator_lock_);
   void InitNativeMethods() REQUIRES(!Locks::mutator_lock_);
   void RegisterRuntimeNativeMethods(JNIEnv* env);
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b59606a..a8133a1 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -491,7 +491,7 @@
 
 Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa,
                                   jobject java_thread) {
-  return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread).Ptr());
+  return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread));
 }
 
 static size_t FixStackSize(size_t stack_size) {
@@ -2728,7 +2728,7 @@
     depth = std::min(depth, traces_length);
   } else {
     // Create java_trace array and place in local reference table
-    mirror::ObjectArray<mirror::StackTraceElement>* java_traces =
+    ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> java_traces =
         class_linker->AllocStackTraceElementArray(soa.Self(), depth);
     if (java_traces == nullptr) {
       return nullptr;
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 02e61d7..370a619 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -506,7 +506,7 @@
         class_linker_->LookupString(string_idx, h_dex_cache.Get());
     ASSERT_TRUE(s != nullptr);
     EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString);
-    EXPECT_EQ(s.Ptr(), h_dex_cache->GetResolvedString(string_idx));
+    EXPECT_OBJ_PTR_EQ(s, h_dex_cache->GetResolvedString(string_idx));
   }
   Runtime::Current()->RollbackAndExitTransactionMode();
   // Check that the string did not stay resolved.
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 838d7f1..32aa86d 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -28,6 +28,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "dex/art_dex_file_loader.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/dex_file.h"
 #include "dex/dex_file_loader.h"
 #include "dex/hidden_api_access_flags.h"
@@ -283,30 +284,25 @@
   std::unordered_set<const DexFile::CodeItem*> unquickened_code_item;
   CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin,
                                                                   quickening_info));
-  for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) {
-    const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i);
-    const uint8_t* class_data = target_dex_file.GetClassData(class_def);
-    if (class_data != nullptr) {
-      for (ClassDataItemIterator class_it(target_dex_file, class_data);
-           class_it.HasNext();
-           class_it.Next()) {
-        if (class_it.IsAtMethod()) {
-          const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem();
-          if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
-            const uint32_t offset = accessor.GetOffset(class_it.GetMemberIndex());
-            // Offset being 0 means not quickened.
-            if (offset != 0u) {
-              ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset);
-              optimizer::ArtDecompileDEX(
-                  target_dex_file,
-                  *code_item,
-                  quicken_data,
-                  decompile_return_instruction);
-            }
-          }
+  for (ClassAccessor class_accessor : target_dex_file.GetClasses()) {
+    for (const ClassAccessor::Method& method : class_accessor.GetMethods()) {
+      const DexFile::CodeItem* code_item = method.GetCodeItem();
+      if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) {
+        const uint32_t offset = accessor.GetOffset(method.GetIndex());
+        // Offset being 0 means not quickened.
+        if (offset != 0u) {
+          ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset);
+          optimizer::ArtDecompileDEX(
+              target_dex_file,
+              *code_item,
+              quicken_data,
+              decompile_return_instruction);
         }
-        DexFile::UnHideAccessFlags(class_it);
       }
+      method.UnHideAccessFlags();
+    }
+    for (const ClassAccessor::Field& field : class_accessor.GetFields()) {
+      field.UnHideAccessFlags();
     }
   }
 }
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 2e3a659..5961748 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -35,6 +35,7 @@
 #include "class_linker.h"
 #include "class_root.h"
 #include "compiler_callbacks.h"
+#include "dex/class_accessor-inl.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_exception_helpers.h"
@@ -190,11 +191,6 @@
                      error);
 }
 
-template <bool kDirect>
-static bool HasNextMethod(ClassDataItemIterator* it) {
-  return kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod();
-}
-
 static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) {
   static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure
                     && FailureKind::kSoftFailure < FailureKind::kHardFailure,
@@ -207,80 +203,6 @@
   types |= fd.types;
 }
 
-template <bool kDirect>
-MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
-                                                          ClassLinker* linker,
-                                                          const DexFile* dex_file,
-                                                          const DexFile::ClassDef& class_def,
-                                                          ClassDataItemIterator* it,
-                                                          Handle<mirror::DexCache> dex_cache,
-                                                          Handle<mirror::ClassLoader> class_loader,
-                                                          CompilerCallbacks* callbacks,
-                                                          bool allow_soft_failures,
-                                                          HardFailLogMode log_level,
-                                                          bool need_precise_constants,
-                                                          std::string* error_string) {
-  DCHECK(it != nullptr);
-
-  MethodVerifier::FailureData failure_data;
-
-  int64_t previous_method_idx = -1;
-  while (HasNextMethod<kDirect>(it)) {
-    self->AllowThreadSuspension();
-    uint32_t method_idx = it->GetMemberIndex();
-    if (method_idx == previous_method_idx) {
-      // smali can create dex files with two encoded_methods sharing the same method_idx
-      // http://code.google.com/p/smali/issues/detail?id=119
-      it->Next();
-      continue;
-    }
-    previous_method_idx = method_idx;
-    InvokeType type = it->GetMethodInvokeType(class_def);
-    ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
-        method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
-    if (method == nullptr) {
-      DCHECK(self->IsExceptionPending());
-      // We couldn't resolve the method, but continue regardless.
-      self->ClearException();
-    } else {
-      DCHECK(method->GetDeclaringClassUnchecked() != nullptr) << type;
-    }
-    StackHandleScope<1> hs(self);
-    std::string hard_failure_msg;
-    MethodVerifier::FailureData result = VerifyMethod(self,
-                                                      method_idx,
-                                                      dex_file,
-                                                      dex_cache,
-                                                      class_loader,
-                                                      class_def,
-                                                      it->GetMethodCodeItem(),
-                                                      method,
-                                                      it->GetMethodAccessFlags(),
-                                                      callbacks,
-                                                      allow_soft_failures,
-                                                      log_level,
-                                                      need_precise_constants,
-                                                      &hard_failure_msg);
-    if (result.kind == FailureKind::kHardFailure) {
-      if (failure_data.kind == FailureKind::kHardFailure) {
-        // If we logged an error before, we need a newline.
-        *error_string += "\n";
-      } else {
-        // If we didn't log a hard failure before, print the header of the message.
-        *error_string += "Verifier rejected class ";
-        *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
-        *error_string += ":";
-      }
-      *error_string += " ";
-      *error_string += hard_failure_msg;
-    }
-    failure_data.Merge(result);
-    it->Next();
-  }
-
-  return failure_data;
-}
-
 FailureKind MethodVerifier::VerifyClass(Thread* self,
                                         const DexFile* dex_file,
                                         Handle<mirror::DexCache> dex_cache,
@@ -300,52 +222,72 @@
     return FailureKind::kHardFailure;
   }
 
-  const uint8_t* class_data = dex_file->GetClassData(class_def);
-  if (class_data == nullptr) {
-    // empty class, probably a marker interface
-    return FailureKind::kNoFailure;
+  ClassAccessor accessor(*dex_file, class_def);
+
+  int64_t previous_method_idx[2] = { -1, -1 };
+  MethodVerifier::FailureData failure_data;
+  ClassLinker* const linker = Runtime::Current()->GetClassLinker();
+
+  for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+    int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u];
+    self->AllowThreadSuspension();
+    const uint32_t method_idx = method.GetIndex();
+    if (method_idx == *previous_idx) {
+      // smali can create dex files with two encoded_methods sharing the same method_idx
+      // http://code.google.com/p/smali/issues/detail?id=119
+      continue;
+    }
+    *previous_idx = method_idx;
+    const InvokeType type = method.GetInvokeType(class_def.access_flags_);
+    ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
+        method_idx, dex_cache, class_loader, /* referrer */ nullptr, type);
+    if (resolved_method == nullptr) {
+      DCHECK(self->IsExceptionPending());
+      // We couldn't resolve the method, but continue regardless.
+      self->ClearException();
+    } else {
+      DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type;
+    }
+    std::string hard_failure_msg;
+    MethodVerifier::FailureData result = VerifyMethod(self,
+                                                      method_idx,
+                                                      dex_file,
+                                                      dex_cache,
+                                                      class_loader,
+                                                      class_def,
+                                                      method.GetCodeItem(),
+                                                      resolved_method,
+                                                      method.GetAccessFlags(),
+                                                      callbacks,
+                                                      allow_soft_failures,
+                                                      log_level,
+                                                      /*need_precise_constants*/ false,
+                                                      &hard_failure_msg);
+    if (result.kind == FailureKind::kHardFailure) {
+      if (failure_data.kind == FailureKind::kHardFailure) {
+        // If we logged an error before, we need a newline.
+        *error += "\n";
+      } else {
+        // If we didn't log a hard failure before, print the header of the message.
+        *error += "Verifier rejected class ";
+        *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def));
+        *error += ":";
+      }
+      *error += " ";
+      *error += hard_failure_msg;
+    }
+    failure_data.Merge(result);
   }
-  ClassDataItemIterator it(*dex_file, class_data);
-  it.SkipAllFields();
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  // Direct methods.
-  MethodVerifier::FailureData data1 = VerifyMethods<true>(self,
-                                                          linker,
-                                                          dex_file,
-                                                          class_def,
-                                                          &it,
-                                                          dex_cache,
-                                                          class_loader,
-                                                          callbacks,
-                                                          allow_soft_failures,
-                                                          log_level,
-                                                          false /* need precise constants */,
-                                                          error);
-  // Virtual methods.
-  MethodVerifier::FailureData data2 = VerifyMethods<false>(self,
-                                                           linker,
-                                                           dex_file,
-                                                           class_def,
-                                                           &it,
-                                                           dex_cache,
-                                                           class_loader,
-                                                           callbacks,
-                                                           allow_soft_failures,
-                                                           log_level,
-                                                           false /* need precise constants */,
-                                                           error);
 
-  data1.Merge(data2);
-
-  if (data1.kind == FailureKind::kNoFailure) {
+  if (failure_data.kind == FailureKind::kNoFailure) {
     return FailureKind::kNoFailure;
   } else {
-    if ((data1.types & VERIFY_ERROR_LOCKING) != 0) {
+    if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) {
       // Print a warning about expected slow-down. Use a string temporary to print one contiguous
       // warning.
       std::string tmp =
           StringPrintf("Class %s failed lock verification and will run slower.",
-                       PrettyDescriptor(dex_file->GetClassDescriptor(class_def)).c_str());
+                       PrettyDescriptor(accessor.GetDescriptor()).c_str());
       if (!gPrintedDxMonitorText) {
         tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n"
                     "and incorrect proguard optimizations.";
@@ -353,7 +295,7 @@
       }
       LOG(WARNING) << tmp;
     }
-    return data1.kind;
+    return failure_data.kind;
   }
 }
 
@@ -1924,15 +1866,11 @@
 static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) {
   const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx);
   DCHECK(class_def != nullptr);
-  const uint8_t* class_data = dex_file.GetClassData(*class_def);
-  DCHECK(class_data != nullptr);
-  ClassDataItemIterator it(dex_file, class_data);
-  it.SkipStaticFields();
-  while (it.HasNextInstanceField()) {
-    if ((it.GetFieldAccessFlags() & kAccFinal) != 0) {
-      return it.GetMemberIndex();
+  ClassAccessor accessor(dex_file, *class_def);
+  for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) {
+    if (field.IsFinal()) {
+      return field.GetIndex();
     }
-    it.Next();
   }
   return dex::kDexNoIndex;
 }
@@ -2932,7 +2870,7 @@
             : called_method->LookupResolvedReturnType();
         if (return_type_class != nullptr) {
           return_type = &FromClass(return_type_descriptor,
-                                   return_type_class.Ptr(),
+                                   return_type_class,
                                    return_type_class->CannotBeAssignedFromOtherTypes());
         } else {
           DCHECK(!can_load_classes_ || self_->IsExceptionPending());
@@ -3685,7 +3623,7 @@
   }
 
   // Record result of class resolution attempt.
-  VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass.Ptr());
+  VerifierDeps::MaybeRecordClassResolution(*dex_file_, class_idx, klass);
 
   // If requested, check if access is allowed. Unresolved types are included in this check, as the
   // interpreter only tests whether access is allowed when a class is not pre-verified and runs in
@@ -4628,9 +4566,7 @@
     std::string temp;
     ObjPtr<mirror::Class> klass = field->GetDeclaringClass();
     const RegType& field_klass =
-        FromClass(klass->GetDescriptor(&temp),
-                  klass.Ptr(),
-                  klass->CannotBeAssignedFromOtherTypes());
+        FromClass(klass->GetDescriptor(&temp), klass, klass->CannotBeAssignedFromOtherTypes());
     if (obj_type.IsUninitializedTypes()) {
       // Field accesses through uninitialized references are only allowable for constructors where
       // the field is declared in this class.
@@ -4731,7 +4667,7 @@
         can_load_classes_ ? field->ResolveType() : field->LookupResolvedType();
     if (field_type_class != nullptr) {
       field_type = &FromClass(field->GetTypeDescriptor(),
-                              field_type_class.Ptr(),
+                              field_type_class,
                               field_type_class->CannotBeAssignedFromOtherTypes());
     } else {
       DCHECK(!can_load_classes_ || self_->IsExceptionPending());
@@ -4919,7 +4855,7 @@
           : method_being_verified_->LookupResolvedReturnType();
       if (return_type_class != nullptr) {
         return_type_ = &FromClass(method_being_verified_->GetReturnTypeDescriptor(),
-                                  return_type_class.Ptr(),
+                                  return_type_class,
                                   return_type_class->CannotBeAssignedFromOtherTypes());
       } else {
         DCHECK(!can_load_classes_ || self_->IsExceptionPending());
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index ae7481c..9890af9 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -275,23 +275,6 @@
     void Merge(const FailureData& src);
   };
 
-  // Verify all direct or virtual methods of a class. The method assumes that the iterator is
-  // positioned correctly, and the iterator will be updated.
-  template <bool kDirect>
-  static FailureData VerifyMethods(Thread* self,
-                                   ClassLinker* linker,
-                                   const DexFile* dex_file,
-                                   const DexFile::ClassDef& class_def,
-                                   ClassDataItemIterator* it,
-                                   Handle<mirror::DexCache> dex_cache,
-                                   Handle<mirror::ClassLoader> class_loader,
-                                   CompilerCallbacks* callbacks,
-                                   bool allow_soft_failures,
-                                   HardFailLogMode log_level,
-                                   bool need_precise_constants,
-                                   std::string* error_string)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   /*
    * Perform verification on a single method.
    *
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 73e516c..4a3f9e6 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -807,7 +807,7 @@
     }
     // Note: The following lookup invalidates existing ObjPtr<>s.
     ObjPtr<mirror::Class> array_class =
-        Runtime::Current()->GetClassLinker()->FindArrayClass(self, &common_elem);
+        Runtime::Current()->GetClassLinker()->FindArrayClass(self, common_elem);
     if (UNLIKELY(array_class == nullptr)) {
       self->AssertPendingException();
       return nullptr;
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 500cc37..fb91976 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -384,7 +384,7 @@
   // Find a boundary making `source` inherit from `destination`. We must find one.
   for (const ObjPtr<mirror::Class>& boundary : boundaries) {
     if (destination->IsAssignableFrom(boundary)) {
-      return boundary.Ptr();
+      return boundary;
     }
   }
   LOG(FATAL) << "Should have found a classpath boundary";
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
index c113042..c6fd56f 100644
--- a/test/497-inlining-and-class-loader/clear_dex_cache.cc
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -52,11 +52,11 @@
     uint32_t index = pair.index;
     ArtMethod* method = pair.object;
     if (sizeof(void*) == 4) {
-      ObjPtr<mirror::IntArray> int_array = down_cast<mirror::IntArray*>(decoded_array.Ptr());
+      ObjPtr<mirror::IntArray> int_array = ObjPtr<mirror::IntArray>::DownCast(decoded_array);
       int_array->Set(2u * i, index);
       int_array->Set(2u * i + 1u, static_cast<jint>(reinterpret_cast<uintptr_t>(method)));
     } else {
-      ObjPtr<mirror::LongArray> long_array = down_cast<mirror::LongArray*>(decoded_array.Ptr());
+      ObjPtr<mirror::LongArray> long_array = ObjPtr<mirror::LongArray>::DownCast(decoded_array);
       long_array->Set(2u * i, index);
       long_array->Set(2u * i + 1u, reinterpret_cast64<jlong>(method));
     }
diff --git a/test/911-get-stack-trace/check b/test/911-get-stack-trace/check
deleted file mode 100644
index ee00266..0000000
--- a/test/911-get-stack-trace/check
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-if [[ "$DX" == 'd8' ]]; then
-  patch -p0 expected.txt < expected_d8.diff
-fi
-
-./default-check "$@"
-if [[ "$?" == "0" ]]; then
-  exit 0;
-fi
-
-# We cannot always correctly determine if D8 was used because of (b/68406220).
-# So we are just going to try to see it matches the expect output of D8 no
-# matter what.
-patch -p0 expected.txt < expected_d8.diff
-
-./default-check "$@"
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index 8177f49..b0a400a 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -9,19 +9,19 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 34 25
+ doTest ()V 33 25
  run ()V 0 25
 ---------
  print (Ljava/lang/Thread;II)V 0 38
@@ -29,19 +29,19 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 38 26
+ doTest ()V 37 26
  run ()V 0 25
 ---------
  getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
@@ -54,12 +54,12 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
 From bottom
 ---------
  run ()V 0 25
 ---------
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  doTest ()V 60 32
@@ -67,7 +67,7 @@
 ---------
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
 
@@ -76,68 +76,76 @@
 ################################
 From top
 ---------
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 28
 ---------
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 28
 ---------
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
 ---------
+ wait ()V 2 568
+ printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
 From bottom
 ---------
  run ()V 4 28
 ---------
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 28
 ---------
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
 
 ###########################
@@ -145,20 +153,20 @@
 ###########################
 From top
 ---------
- printOrWait (IILart/ControlData;)V 44 54
+ printOrWait (IILart/ControlData;)V 45 54
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 61
@@ -166,29 +174,29 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 61
 ---------
- printOrWait (IILart/ControlData;)V 44 54
+ printOrWait (IILart/ControlData;)V 45 54
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
 ---------
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
 From bottom
@@ -196,15 +204,15 @@
  run ()V 4 61
 ---------
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 61
 ---------
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
 
 ################################
@@ -263,7 +271,9 @@
 <not printed>
 ---------
 AllTraces Thread 0
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -271,7 +281,9 @@
 
 ---------
 AllTraces Thread 1
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -279,7 +291,9 @@
 
 ---------
 AllTraces Thread 2
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -287,7 +301,9 @@
 
 ---------
 AllTraces Thread 3
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -295,7 +311,9 @@
 
 ---------
 AllTraces Thread 4
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -303,7 +321,9 @@
 
 ---------
 AllTraces Thread 5
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -311,7 +331,9 @@
 
 ---------
 AllTraces Thread 6
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -319,7 +341,9 @@
 
 ---------
 AllTraces Thread 7
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -327,7 +351,9 @@
 
 ---------
 AllTraces Thread 8
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -335,7 +361,9 @@
 
 ---------
 AllTraces Thread 9
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -360,7 +388,7 @@
 Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
- doTest ()V 122 59
+ doTest ()V 120 59
  run ()V 24 37
 
 ---------
@@ -368,210 +396,230 @@
 <not printed>
 ---------
 AllTraces Thread 0
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 1
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 2
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 3
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 4
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 5
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 6
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 7
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 8
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
 
 ---------
 AllTraces Thread 9
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 47
@@ -595,7 +643,7 @@
 Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
- doTest ()V 127 61
+ doTest ()V 125 61
  run ()V 24 37
 
 ---------
@@ -627,12 +675,14 @@
 Test911
  getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
  printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 112 54
+ doTest ()V 110 54
  run ()V 32 41
 
 ---------
 ThreadListTraces Thread 0
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -640,7 +690,9 @@
 
 ---------
 ThreadListTraces Thread 2
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -648,7 +700,9 @@
 
 ---------
 ThreadListTraces Thread 4
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -656,7 +710,9 @@
 
 ---------
 ThreadListTraces Thread 6
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -664,7 +720,9 @@
 
 ---------
 ThreadListTraces Thread 8
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
@@ -674,110 +732,120 @@
 Test911
  getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
  printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 117 56
+ doTest ()V 115 56
  run ()V 32 41
 
 ---------
 ThreadListTraces Thread 0
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
 
 ---------
 ThreadListTraces Thread 2
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
 
 ---------
 ThreadListTraces Thread 4
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
 
 ---------
 ThreadListTraces Thread 6
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
 
 ---------
 ThreadListTraces Thread 8
- wait ()V -1 -2
+ wait (JI)V -1 -2
+ wait (J)V 1 442
+ wait ()V 2 568
  printOrWait (IILart/ControlData;)V 24 47
  baz (IIILart/ControlData;)Ljava/lang/Object; 2 32
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
+ baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
  run ()V 4 37
@@ -789,7 +857,7 @@
 4
 JVMTI_ERROR_ILLEGAL_ARGUMENT
 [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff]
-[public static void art.Frames.doTestSameThread(), 35]
+[public static void art.Frames.doTestSameThread(), 40]
 [public static void art.Frames.doTest() throws java.lang.Exception, 0]
 [public void art.Test911$1.run(), 28]
 JVMTI_ERROR_NO_MORE_FRAMES
@@ -797,23 +865,25 @@
 ################################
 ### Other thread (suspended) ###
 ################################
-18
+20
 JVMTI_ERROR_ILLEGAL_ARGUMENT
-[public final native void java.lang.Object.wait() throws java.lang.InterruptedException, ffffffff]
+[public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, ffffffff]
+[public final void java.lang.Object.wait(long) throws java.lang.InterruptedException, 1]
+[public final void java.lang.Object.wait() throws java.lang.InterruptedException, 2]
 [private static void art.Recurse.printOrWait(int,int,art.ControlData), 18]
 [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
 [public void art.Frames$1.run(), 4]
@@ -824,20 +894,20 @@
 ###########################
 17
 JVMTI_ERROR_ILLEGAL_ARGUMENT
-[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c]
+[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d]
 [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
-[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
+[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
 [private static long art.Recurse.bar(int,int,int,art.ControlData), 0]
 [public static int art.Recurse.foo(int,int,int,art.ControlData), 0]
 [public void art.Frames$2.run(), 4]
diff --git a/test/911-get-stack-trace/expected_d8.diff b/test/911-get-stack-trace/expected_d8.diff
deleted file mode 100644
index c12015a..0000000
--- a/test/911-get-stack-trace/expected_d8.diff
+++ /dev/null
@@ -1,456 +0,0 @@
-12c12
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-15c15
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-18c18
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-21c21
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-24c24
-<  doTest ()V 34 25
----
->  doTest ()V 33 25
-32c32
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-35c35
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-38c38
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-41c41
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-44c44
-<  doTest ()V 38 26
----
->  doTest ()V 37 26
-57c57
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-62c62
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-70c70
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-84c84
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-87c87
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-90c90
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-93c93
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-102c102
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-105c105
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-108c108
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-111c111
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-125c125
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-132c132
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-137c137
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-140c140
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-148c148
-<  printOrWait (IILart/ControlData;)V 44 54
----
->  printOrWait (IILart/ControlData;)V 45 54
-152c152
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-155c155
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-158c158
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-161c161
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-169c169
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-172c172
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-175c175
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-178c178
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-183c183
-<  printOrWait (IILart/ControlData;)V 44 54
----
->  printOrWait (IILart/ControlData;)V 45 54
-187c187
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-191c191
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-199c199
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-204c204
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-207c207
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-363c363
-<  doTest ()V 122 59
----
->  doTest ()V 120 59
-376c376
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-379c379
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-382c382
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-385c385
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-397c397
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-400c400
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-403c403
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-406c406
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-418c418
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-421c421
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-424c424
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-427c427
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-439c439
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-442c442
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-445c445
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-448c448
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-460c460
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-463c463
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-466c466
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-469c469
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-481c481
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-484c484
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-487c487
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-490c490
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-502c502
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-505c505
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-508c508
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-511c511
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-523c523
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-526c526
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-529c529
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-532c532
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-544c544
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-547c547
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-550c550
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-553c553
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-565c565
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-568c568
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-571c571
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-574c574
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-598c598
-<  doTest ()V 127 61
----
->  doTest ()V 125 61
-630c630
-<  doTest ()V 112 54
----
->  doTest ()V 110 54
-677c677
-<  doTest ()V 117 56
----
->  doTest ()V 115 56
-687c687
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-690c690
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-693c693
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-696c696
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-708c708
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-711c711
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-714c714
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-717c717
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-729c729
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-732c732
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-735c735
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-738c738
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-750c750
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-753c753
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-756c756
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-759c759
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-771c771
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-774c774
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-777c777
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-780c780
-<  baz (IIILart/ControlData;)Ljava/lang/Object; 9 34
----
->  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
-792c792
-< [public static void art.Frames.doTestSameThread(), 35]
----
-> [public static void art.Frames.doTestSameThread(), 40]
-807c807
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-810c810
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-813c813
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-816c816
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-827c827
-< [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c]
----
-> [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d]
-831c831
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-834c834
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-837c837
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
-840c840
-< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9]
----
-> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8]
diff --git a/test/911-get-stack-trace/src/art/AllTraces.java b/test/911-get-stack-trace/src/art/AllTraces.java
index d73f78b..507925c 100644
--- a/test/911-get-stack-trace/src/art/AllTraces.java
+++ b/test/911-get-stack-trace/src/art/AllTraces.java
@@ -56,7 +56,7 @@
 
     printAll(0);
 
-    printAll(5);
+    printAll(7);
 
     printAll(25);
 
diff --git a/test/911-get-stack-trace/src/art/OtherThread.java b/test/911-get-stack-trace/src/art/OtherThread.java
index 675bff5..3f5ae59 100644
--- a/test/911-get-stack-trace/src/art/OtherThread.java
+++ b/test/911-get-stack-trace/src/art/OtherThread.java
@@ -36,8 +36,8 @@
     System.out.println("From top");
     PrintThread.print(t, 0, 25);
     PrintThread.print(t, 1, 25);
-    PrintThread.print(t, 0, 5);
-    PrintThread.print(t, 2, 5);
+    PrintThread.print(t, 0, 7);
+    PrintThread.print(t, 2, 7);
 
     System.out.println("From bottom");
     PrintThread.print(t, -1, 25);
diff --git a/test/911-get-stack-trace/src/art/ThreadListTraces.java b/test/911-get-stack-trace/src/art/ThreadListTraces.java
index 0de93de..9b27e72 100644
--- a/test/911-get-stack-trace/src/art/ThreadListTraces.java
+++ b/test/911-get-stack-trace/src/art/ThreadListTraces.java
@@ -51,7 +51,7 @@
 
     printList(list, 0);
 
-    printList(list, 5);
+    printList(list, 7);
 
     printList(list, 25);
 
diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc
index 7d7e5f2..7a9b8fb 100644
--- a/tools/dexanalyze/dexanalyze.cc
+++ b/tools/dexanalyze/dexanalyze.cc
@@ -116,12 +116,14 @@
       }
     }
 
-    bool ProcessDexFile(const DexFile& dex_file) {
+    bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
       for (std::unique_ptr<Experiment>& experiment : experiments_) {
-        experiment->ProcessDexFile(dex_file);
+        experiment->ProcessDexFiles(dex_files);
       }
-      total_size_ += dex_file.Size();
-      ++dex_count_;
+      for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+        total_size_ += dex_file->Size();
+      }
+      dex_count_ += dex_files.size();
       return true;
     }
 
@@ -169,18 +171,16 @@
         LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl;
         return kExitCodeFailedToOpenDex;
       }
-      for (std::unique_ptr<const DexFile>& dex_file : dex_files) {
-        if (options.dump_per_input_dex_) {
-          Analysis current(&options);
-          if (!current.ProcessDexFile(*dex_file)) {
-            LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
-            return kExitCodeFailedToProcessDex;
-          }
-          LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl;
-          current.Dump(LOG_STREAM(INFO));
+      if (options.dump_per_input_dex_) {
+        Analysis current(&options);
+        if (!current.ProcessDexFiles(dex_files)) {
+          LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg;
+          return kExitCodeFailedToProcessDex;
         }
-        cumulative.ProcessDexFile(*dex_file);
+        LOG(INFO) << "Analysis for " << filename << std::endl;
+        current.Dump(LOG_STREAM(INFO));
       }
+      cumulative.ProcessDexFiles(dex_files);
     }
     LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl;
     cumulative.Dump(LOG_STREAM(INFO));
diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc
index 1a3b89c..244f45b 100644
--- a/tools/dexanalyze/dexanalyze_experiments.cc
+++ b/tools/dexanalyze/dexanalyze_experiments.cc
@@ -75,86 +75,95 @@
   return len;
 }
 
-void AnalyzeDebugInfo::ProcessDexFile(const DexFile& dex_file) {
+void Experiment::ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
+  for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    ProcessDexFile(*dex_file);
+  }
+}
+
+void AnalyzeDebugInfo::ProcessDexFiles(
+    const std::vector<std::unique_ptr<const DexFile>>& dex_files) {
   std::set<const uint8_t*> seen;
   std::vector<size_t> counts(256, 0u);
   std::vector<size_t> opcode_counts(256, 0u);
   std::set<std::vector<uint8_t>> unique_non_header;
-  for (ClassAccessor accessor : dex_file.GetClasses()) {
-    for (const ClassAccessor::Method& method : accessor.GetMethods()) {
-      CodeItemDebugInfoAccessor code_item(dex_file, method.GetCodeItem(), method.GetIndex());
-      const uint8_t* debug_info = dex_file.GetDebugInfoStream(code_item.DebugInfoOffset());
-      if (debug_info != nullptr && seen.insert(debug_info).second) {
-        const uint8_t* stream = debug_info;
-        DecodeUnsignedLeb128(&stream);  // line_start
-        uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
-        for (uint32_t i = 0; i < parameters_size; ++i) {
-          DecodeUnsignedLeb128P1(&stream);  // Parameter name.
-        }
-        bool done = false;
-        const uint8_t* after_header_start = stream;
-        while (!done) {
-          const uint8_t* const op_start = stream;
-          uint8_t opcode = *stream++;
-          ++opcode_counts[opcode];
-          ++total_opcode_bytes_;
-          switch (opcode) {
-            case DexFile::DBG_END_SEQUENCE:
-              ++total_end_seq_bytes_;
-              done = true;
-              break;
-            case DexFile::DBG_ADVANCE_PC:
-              DecodeUnsignedLeb128(&stream);  // addr_diff
-              total_advance_pc_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_ADVANCE_LINE:
-              DecodeSignedLeb128(&stream);  // line_diff
-              total_advance_line_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_START_LOCAL:
-              DecodeUnsignedLeb128(&stream);  // register_num
-              DecodeUnsignedLeb128P1(&stream);  // name_idx
-              DecodeUnsignedLeb128P1(&stream);  // type_idx
-              total_start_local_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_START_LOCAL_EXTENDED:
-              DecodeUnsignedLeb128(&stream);  // register_num
-              DecodeUnsignedLeb128P1(&stream);  // name_idx
-              DecodeUnsignedLeb128P1(&stream);  // type_idx
-              DecodeUnsignedLeb128P1(&stream);  // sig_idx
-              total_start_local_extended_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_END_LOCAL:
-              DecodeUnsignedLeb128(&stream);  // register_num
-              total_end_local_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_RESTART_LOCAL:
-              DecodeUnsignedLeb128(&stream);  // register_num
-              total_restart_local_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_SET_PROLOGUE_END:
-            case DexFile::DBG_SET_EPILOGUE_BEGIN:
-              total_epilogue_bytes_ += stream - op_start;
-              break;
-            case DexFile::DBG_SET_FILE: {
-              DecodeUnsignedLeb128P1(&stream);  // name_idx
-              total_set_file_bytes_ += stream - op_start;
-              break;
-            }
-            default: {
-              total_other_bytes_ += stream - op_start;
-              break;
+  for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+    for (ClassAccessor accessor : dex_file->GetClasses()) {
+      for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+        CodeItemDebugInfoAccessor code_item(*dex_file, method.GetCodeItem(), method.GetIndex());
+        const uint8_t* debug_info = dex_file->GetDebugInfoStream(code_item.DebugInfoOffset());
+        if (debug_info != nullptr && seen.insert(debug_info).second) {
+          const uint8_t* stream = debug_info;
+          DecodeUnsignedLeb128(&stream);  // line_start
+          uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+          for (uint32_t i = 0; i < parameters_size; ++i) {
+            DecodeUnsignedLeb128P1(&stream);  // Parameter name.
+          }
+          bool done = false;
+          const uint8_t* after_header_start = stream;
+          while (!done) {
+            const uint8_t* const op_start = stream;
+            uint8_t opcode = *stream++;
+            ++opcode_counts[opcode];
+            ++total_opcode_bytes_;
+            switch (opcode) {
+              case DexFile::DBG_END_SEQUENCE:
+                ++total_end_seq_bytes_;
+                done = true;
+                break;
+              case DexFile::DBG_ADVANCE_PC:
+                DecodeUnsignedLeb128(&stream);  // addr_diff
+                total_advance_pc_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_ADVANCE_LINE:
+                DecodeSignedLeb128(&stream);  // line_diff
+                total_advance_line_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_START_LOCAL:
+                DecodeUnsignedLeb128(&stream);  // register_num
+                DecodeUnsignedLeb128P1(&stream);  // name_idx
+                DecodeUnsignedLeb128P1(&stream);  // type_idx
+                total_start_local_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_START_LOCAL_EXTENDED:
+                DecodeUnsignedLeb128(&stream);  // register_num
+                DecodeUnsignedLeb128P1(&stream);  // name_idx
+                DecodeUnsignedLeb128P1(&stream);  // type_idx
+                DecodeUnsignedLeb128P1(&stream);  // sig_idx
+                total_start_local_extended_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_END_LOCAL:
+                DecodeUnsignedLeb128(&stream);  // register_num
+                total_end_local_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_RESTART_LOCAL:
+                DecodeUnsignedLeb128(&stream);  // register_num
+                total_restart_local_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_SET_PROLOGUE_END:
+              case DexFile::DBG_SET_EPILOGUE_BEGIN:
+                total_epilogue_bytes_ += stream - op_start;
+                break;
+              case DexFile::DBG_SET_FILE: {
+                DecodeUnsignedLeb128P1(&stream);  // name_idx
+                total_set_file_bytes_ += stream - op_start;
+                break;
+              }
+              default: {
+                total_other_bytes_ += stream - op_start;
+                break;
+              }
             }
           }
-        }
-        const size_t bytes = stream - debug_info;
-        total_bytes_ += bytes;
-        total_non_header_bytes_ += stream - after_header_start;
-        if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) {
-          total_unique_non_header_bytes_ += stream - after_header_start;
-        }
-        for (size_t i = 0; i < bytes; ++i) {
-          ++counts[debug_info[i]];
+          const size_t bytes = stream - debug_info;
+          total_bytes_ += bytes;
+          total_non_header_bytes_ += stream - after_header_start;
+          if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) {
+            total_unique_non_header_bytes_ += stream - after_header_start;
+          }
+          for (size_t i = 0; i < bytes; ++i) {
+            ++counts[debug_info[i]];
+          }
         }
       }
     }
diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h
index a2621c8..2be53d6 100644
--- a/tools/dexanalyze/dexanalyze_experiments.h
+++ b/tools/dexanalyze/dexanalyze_experiments.h
@@ -18,7 +18,9 @@
 #define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_
 
 #include <iosfwd>
+#include <memory>
 #include <set>
+#include <vector>
 
 namespace art {
 
@@ -30,7 +32,8 @@
 class Experiment {
  public:
   virtual ~Experiment() {}
-  virtual void ProcessDexFile(const DexFile& dex_file) = 0;
+  virtual void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
+  virtual void ProcessDexFile(const DexFile&) {}
   virtual void Dump(std::ostream& os, uint64_t total_size) const = 0;
 };
 
@@ -54,7 +57,7 @@
 // Analyze debug info sizes.
 class AnalyzeDebugInfo  : public Experiment {
  public:
-  void ProcessDexFile(const DexFile& dex_file);
+  void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files);
   void Dump(std::ostream& os, uint64_t total_size) const;
 
  private:
@@ -112,7 +115,7 @@
   size_t total_super_ = 0;
 };
 
-// Measure various code metrics including args per invoke-virtual, fill/spill move paterns.
+// Measure various code metrics including args per invoke-virtual, fill/spill move patterns.
 class CodeMetrics : public Experiment {
  public:
   void ProcessDexFile(const DexFile& dex_file);