Merge "ARM: VIXL32: Fix the assembler usage in the intrinsics."
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 99b0ac1..174e85e 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -26,6 +26,7 @@
 #include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/length_prefixed_array.h"
+#include "dex_file_types.h"
 #include "method_reference.h"
 
 namespace art {
@@ -302,9 +303,9 @@
     return target_dex_file_;
   }
 
-  uint32_t TargetTypeIndex() const {
+  dex::TypeIndex TargetTypeIndex() const {
     DCHECK(patch_type_ == Type::kType || patch_type_ == Type::kTypeRelative);
-    return type_idx_;
+    return dex::TypeIndex(type_idx_);
   }
 
   const DexFile* TargetStringDexFile() const {
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e19fb7b..1bdace9 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -230,7 +230,7 @@
         const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
                                                                 inst->VRegA_21c()));
         const verifier::RegType& cast_type =
-            method_verifier->ResolveCheckedClass(inst->VRegB_21c());
+            method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
         is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type, method_verifier);
       } else {
         const verifier::RegType& array_type(line->GetRegisterType(method_verifier,
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 9711516..f056dd3 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -38,7 +38,7 @@
 
 inline mirror::Class* CompilerDriver::ResolveClass(
     const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-    Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
+    Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
     const DexCompilationUnit* mUnit) {
   DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
   DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
@@ -141,7 +141,7 @@
     mirror::Class* referrer_class,
     ArtMember* resolved_member,
     uint16_t member_idx,
-    uint32_t* storage_index) {
+    dex::TypeIndex* storage_index) {
   DCHECK(resolved_member->IsStatic());
   if (LIKELY(referrer_class != nullptr)) {
     ObjPtr<mirror::Class> members_class = resolved_member->GetDeclaringClass();
@@ -156,7 +156,7 @@
       // TODO: for images we can elide the static storage base null check
       // if we know there's a non-null entry in the image
       const DexFile* dex_file = dex_cache->GetDexFile();
-      uint32_t storage_idx = DexFile::kDexNoIndex;
+      dex::TypeIndex storage_idx(DexFile::kDexNoIndex16);
       if (LIKELY(members_class->GetDexCache() == dex_cache)) {
         // common case where the dex cache of both the referrer and the member are the same,
         // no need to search the dex file
@@ -166,27 +166,27 @@
         // of the class mentioned in the dex file and there is no dex cache entry.
         storage_idx = resolved_member->GetDeclaringClass()->FindTypeIndexInOtherDexFile(*dex_file);
       }
-      if (storage_idx != DexFile::kDexNoIndex) {
+      if (storage_idx.IsValid()) {
         *storage_index = storage_idx;
         return std::make_pair(true, !resolved_member->IsFinal());
       }
     }
   }
   // Conservative defaults.
-  *storage_index = DexFile::kDexNoIndex;
+  *storage_index = dex::TypeIndex(DexFile::kDexNoIndex16);
   return std::make_pair(false, false);
 }
 
 inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
     mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-    ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) {
+    ArtField* resolved_field, uint16_t field_idx, dex::TypeIndex* storage_index) {
   return IsClassOfStaticMemberAvailableToReferrer(
       dex_cache, referrer_class, resolved_field, field_idx, storage_index);
 }
 
 inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer(
     mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-    ArtMethod* resolved_method, uint16_t method_idx, uint32_t* storage_index) {
+    ArtMethod* resolved_method, uint16_t method_idx, dex::TypeIndex* storage_index) {
   std::pair<bool, bool> result = IsClassOfStaticMemberAvailableToReferrer(
       dex_cache, referrer_class, resolved_method, method_idx, storage_index);
   // Only the first member of `result` is meaningful, as there is no
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index aa0d10b..c62e214 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -969,7 +969,7 @@
   }
   DCHECK(profile_compilation_info_ != nullptr);
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_idx);
-  uint16_t type_idx = class_def.class_idx_;
+  dex::TypeIndex type_idx = class_def.class_idx_;
   bool result = profile_compilation_info_->ContainsClass(dex_file, type_idx);
   if (kDebugProfileGuidedCompilation) {
     LOG(INFO) << "[ProfileGuidedCompilation] " << (result ? "Verified" : "Skipped") << " method:"
@@ -981,7 +981,7 @@
 class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
  public:
   explicit ResolveCatchBlockExceptionsClassVisitor(
-      std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
+      std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve)
      : exceptions_to_resolve_(exceptions_to_resolve) {}
 
   virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1012,8 +1012,8 @@
         has_catch_all = true;
       }
       for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
-        uint16_t encoded_catch_handler_handlers_type_idx =
-            DecodeUnsignedLeb128(&encoded_catch_handler_list);
+        dex::TypeIndex encoded_catch_handler_handlers_type_idx =
+            dex::TypeIndex(DecodeUnsignedLeb128(&encoded_catch_handler_list));
         // Add to set of types to resolve if not already in the dex cache resolved types
         if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx,
                                               pointer_size)) {
@@ -1030,7 +1030,7 @@
     }
   }
 
-  std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve_;
+  std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve_;
 };
 
 class RecordImageClassesVisitor : public ClassVisitor {
@@ -1078,7 +1078,7 @@
   // Resolve exception classes referenced by the loaded classes. The catch logic assumes
   // exceptions are resolved by the verifier when there is a catch block in an interested method.
   // Do this here so that exception classes appear to have been specified image classes.
-  std::set<std::pair<uint16_t, const DexFile*>> unresolved_exception_types;
+  std::set<std::pair<dex::TypeIndex, const DexFile*>> unresolved_exception_types;
   StackHandleScope<1> hs(self);
   Handle<mirror::Class> java_lang_Throwable(
       hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;")));
@@ -1086,8 +1086,8 @@
     unresolved_exception_types.clear();
     ResolveCatchBlockExceptionsClassVisitor visitor(unresolved_exception_types);
     class_linker->VisitClasses(&visitor);
-    for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
-      uint16_t exception_type_idx = exception_type.first;
+    for (const auto& exception_type : unresolved_exception_types) {
+      dex::TypeIndex exception_type_idx = exception_type.first;
       const DexFile* dex_file = exception_type.second;
       StackHandleScope<2> hs2(self);
       Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
@@ -1338,7 +1338,7 @@
 
 bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx,
                                                 Handle<mirror::DexCache> dex_cache,
-                                                uint32_t type_idx) {
+                                                dex::TypeIndex type_idx) {
   // Get type from dex cache assuming it was populated by the verifier
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
   if (resolved_class == nullptr) {
@@ -1367,7 +1367,7 @@
 
 bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
                                                             Handle<mirror::DexCache> dex_cache,
-                                                            uint32_t type_idx,
+                                                            dex::TypeIndex type_idx,
                                                             bool* finalizable) {
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
@@ -1861,7 +1861,7 @@
  public:
   explicit ResolveTypeVisitor(const ParallelCompilationManager* manager) : manager_(manager) {
   }
-  virtual void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
+  void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
   // Class derived values are more complicated, they require the linker and loader.
     ScopedObjectAccess soa(Thread::Current());
     ClassLinker* class_linker = manager_->GetClassLinker();
@@ -1872,7 +1872,10 @@
     Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
         dex_file,
         class_loader.Get())));
-    mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
+    mirror::Class* klass = class_linker->ResolveType(dex_file,
+                                                     dex::TypeIndex(type_idx),
+                                                     dex_cache,
+                                                     class_loader);
 
     if (klass == nullptr) {
       soa.Self()->AssertPendingException();
@@ -1952,9 +1955,9 @@
       for (const DexFile* dex_file : dex_files) {
         // Fetch the list of unverified classes and turn it into a set for faster
         // lookups.
-        const std::vector<uint16_t>& unverified_classes =
+        const std::vector<dex::TypeIndex>& unverified_classes =
             verifier_deps->GetUnverifiedClasses(*dex_file);
-        std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+        std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
         for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
           const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
           const char* descriptor = dex_file->GetClassDescriptor(class_def);
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1bd3546..c7719fb 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -31,6 +31,7 @@
 #include "class_reference.h"
 #include "compiler.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "driver/compiled_method_storage.h"
 #include "jit/offline_profiling_info.h"
 #include "invoke_type.h"
@@ -188,14 +189,14 @@
   // Are runtime access checks necessary in the compiled code?
   bool CanAccessTypeWithoutChecks(uint32_t referrer_idx,
                                   Handle<mirror::DexCache> dex_cache,
-                                  uint32_t type_idx)
+                                  dex::TypeIndex type_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Are runtime access and instantiable checks necessary in the code?
   // out_is_finalizable is set to whether the type is finalizable.
   bool CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
                                               Handle<mirror::DexCache> dex_cache,
-                                              uint32_t type_idx,
+                                              dex::TypeIndex type_idx,
                                               bool* out_is_finalizable)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -207,7 +208,7 @@
 
   mirror::Class* ResolveClass(
       const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
-      Handle<mirror::ClassLoader> class_loader, uint16_t type_index,
+      Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
       const DexCompilationUnit* mUnit)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -234,9 +235,11 @@
 
   // Can we fast-path an SGET/SPUT access to a static field? If yes, compute the type index
   // of the declaring class in the referrer's dex file.
-  std::pair<bool, bool> IsFastStaticField(
-      mirror::DexCache* dex_cache, mirror::Class* referrer_class,
-      ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index)
+  std::pair<bool, bool> IsFastStaticField(mirror::DexCache* dex_cache,
+                                          mirror::Class* referrer_class,
+                                          ArtField* resolved_field,
+                                          uint16_t field_idx,
+                                          dex::TypeIndex* storage_index)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Return whether the declaring class of `resolved_method` is
@@ -248,7 +251,7 @@
                                                 mirror::Class* referrer_class,
                                                 ArtMethod* resolved_method,
                                                 uint16_t method_idx,
-                                                uint32_t* storage_index)
+                                                dex::TypeIndex* storage_index)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Resolve a method. Returns null on failure, including incompatible class change.
@@ -395,7 +398,7 @@
                                                                  mirror::Class* referrer_class,
                                                                  ArtMember* resolved_member,
                                                                  uint16_t member_idx,
-                                                                 uint32_t* storage_index)
+                                                                 dex::TypeIndex* storage_index)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Can `referrer_class` access the resolved `member`?
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 9679a79..f40c712 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -24,6 +24,7 @@
 #include "class_linker-inl.h"
 #include "common_compiler_test.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "gc/heap.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -115,9 +116,9 @@
   }
   EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes());
   for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
-    mirror::Class* type = dex_cache->GetResolvedType(i);
+    mirror::Class* type = dex_cache->GetResolvedType(dex::TypeIndex(i));
     EXPECT_TRUE(type != nullptr) << "type_idx=" << i
-                              << " " << dex.GetTypeDescriptor(dex.GetTypeId(i));
+                              << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i)));
   }
   EXPECT_EQ(dex.NumMethodIds(), dex_cache->NumResolvedMethods());
   auto* cl = Runtime::Current()->GetClassLinker();
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index d7b7403..a882a88 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -32,6 +32,7 @@
 #include "class_linker-inl.h"
 #include "compiled_method.h"
 #include "dex_file-inl.h"
+#include "dex_file_types.h"
 #include "driver/compiler_driver.h"
 #include "elf_file.h"
 #include "elf_utils.h"
@@ -837,19 +838,64 @@
   return true;
 }
 
-class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
+class ImageWriter::PruneClassesVisitor : public ClassVisitor {
  public:
-  explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
+  PruneClassesVisitor(ImageWriter* image_writer, ObjPtr<mirror::ClassLoader> class_loader)
+      : image_writer_(image_writer),
+        class_loader_(class_loader),
+        classes_to_prune_(),
+        defined_class_count_(0u) { }
 
-  bool operator()(ObjPtr<Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+  bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
     if (!image_writer_->KeepClass(klass.Ptr())) {
       classes_to_prune_.insert(klass.Ptr());
+      if (klass->GetClassLoader() == class_loader_) {
+        ++defined_class_count_;
+      }
     }
     return true;
   }
 
-  std::unordered_set<mirror::Class*> classes_to_prune_;
+  size_t Prune() REQUIRES_SHARED(Locks::mutator_lock_) {
+    ClassTable* class_table =
+        Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader_);
+    for (mirror::Class* klass : classes_to_prune_) {
+      std::string storage;
+      const char* descriptor = klass->GetDescriptor(&storage);
+      bool result = class_table->Remove(descriptor);
+      DCHECK(result);
+    }
+    return defined_class_count_;
+  }
+
+ private:
   ImageWriter* const image_writer_;
+  const ObjPtr<mirror::ClassLoader> class_loader_;
+  std::unordered_set<mirror::Class*> classes_to_prune_;
+  size_t defined_class_count_;
+};
+
+class ImageWriter::PruneClassLoaderClassesVisitor : public ClassLoaderVisitor {
+ public:
+  explicit PruneClassLoaderClassesVisitor(ImageWriter* image_writer)
+      : image_writer_(image_writer), removed_class_count_(0) {}
+
+  virtual void Visit(ObjPtr<mirror::ClassLoader> class_loader) OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    PruneClassesVisitor classes_visitor(image_writer_, class_loader);
+    ClassTable* class_table =
+        Runtime::Current()->GetClassLinker()->ClassTableForClassLoader(class_loader);
+    class_table->Visit(classes_visitor);
+    removed_class_count_ += classes_visitor.Prune();
+  }
+
+  size_t GetRemovedClassCount() const {
+    return removed_class_count_;
+  }
+
+ private:
+  ImageWriter* const image_writer_;
+  size_t removed_class_count_;
 };
 
 void ImageWriter::PruneNonImageClasses() {
@@ -861,21 +907,13 @@
   // path dex caches.
   class_linker->ClearClassTableStrongRoots();
 
-  // Make a list of classes we would like to prune.
-  NonImageClassesVisitor visitor(this);
-  class_linker->VisitClasses(&visitor);
-
   // Remove the undesired classes from the class roots.
-  VLOG(compiler) << "Pruning " << visitor.classes_to_prune_.size() << " classes";
-  for (mirror::Class* klass : visitor.classes_to_prune_) {
-    std::string temp;
-    const char* name = klass->GetDescriptor(&temp);
-    VLOG(compiler) << "Pruning class " << name;
-    if (!compile_app_image_) {
-      DCHECK(IsBootClassLoaderClass(klass));
-    }
-    bool result = class_linker->RemoveClass(name, klass->GetClassLoader());
-    DCHECK(result);
+  {
+    ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+    PruneClassLoaderClassesVisitor class_loader_visitor(this);
+    class_loader_visitor.Visit(nullptr);  // Visit boot class loader.
+    class_linker->VisitClassLoaders(&class_loader_visitor);
+    VLOG(compiler) << "Pruned " << class_loader_visitor.GetRemovedClassCount() << " classes";
   }
 
   // Clear references to removed classes from the DexCaches.
@@ -890,9 +928,9 @@
     }
     ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache();
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
-      Class* klass = dex_cache->GetResolvedType(i);
+      Class* klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
       if (klass != nullptr && !KeepClass(klass)) {
-        dex_cache->SetResolvedType(i, nullptr);
+        dex_cache->SetResolvedType(dex::TypeIndex(i), nullptr);
       }
     }
     ArtMethod** resolved_methods = dex_cache->GetResolvedMethods();
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 24fad46..ad6ffd8 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -588,7 +588,8 @@
   class FixupVisitor;
   class GetRootsVisitor;
   class NativeLocationVisitor;
-  class NonImageClassesVisitor;
+  class PruneClassesVisitor;
+  class PruneClassLoaderClassesVisitor;
   class VisitReferencesVisitor;
 
   DISALLOW_COPY_AND_ASSIGN(ImageWriter);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index f9173f5..bde00cf 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -260,16 +260,7 @@
   // Data to write to a separate section.
   dchecked_vector<uint32_t> class_offsets_;
 
-  void InitTypeLookupTable(const DexFile& dex_file, uint8_t* storage) const {
-    lookup_table_.reset(TypeLookupTable::Create(dex_file, storage));
-  }
-
-  TypeLookupTable* GetTypeLookupTable() const {
-    return lookup_table_.get();
-  }
-
  private:
-  mutable std::unique_ptr<TypeLookupTable> lookup_table_;
   size_t GetClassOffsetsRawSize() const {
     return class_offsets_.size() * sizeof(class_offsets_[0]);
   }
@@ -2481,8 +2472,15 @@
 
     // Create the lookup table. When `nullptr` is given as the storage buffer,
     // TypeLookupTable allocates its own and OatDexFile takes ownership.
-    oat_dex_file->InitTypeLookupTable(*opened_dex_files[i], /* storage */ nullptr);
-    TypeLookupTable* table = oat_dex_file->GetTypeLookupTable();
+    const DexFile& dex_file = *opened_dex_files[i];
+    {
+      std::unique_ptr<TypeLookupTable> type_lookup_table =
+          TypeLookupTable::Create(dex_file, /* storage */ nullptr);
+      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();
 
     // Type tables are required to be 4 byte aligned.
     size_t initial_offset = oat_size_;
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 3d08ad3..b92ba76 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -363,6 +363,9 @@
   // Offset of the oat data from the start of the mmapped region of the elf file.
   size_t oat_data_offset_;
 
+  // Fake OatDexFiles to hold type lookup tables for the compiler.
+  std::vector<std::unique_ptr<art::OatDexFile>> type_lookup_table_oat_dex_files_;
+
   // data to write
   std::unique_ptr<OatHeader> oat_header_;
   dchecked_vector<OatDexFile> oat_dex_files_;
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index b7c24ff..dfa1504 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -70,9 +70,9 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);  // array
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);  // i
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -167,9 +167,9 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);  // array
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);  // i
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -231,9 +231,9 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);  // array
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);  // array
   HInstruction* parameter2 = new (&allocator_)
-      HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);  // i
+      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);  // i
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
 
@@ -295,7 +295,7 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_5 = graph_->GetIntConstant(5);
@@ -364,7 +364,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -479,7 +479,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -600,7 +600,7 @@
       constant_10,
       graph->GetCurrentMethod(),
       0,
-      Primitive::kPrimInt,
+      dex::TypeIndex(static_cast<uint16_t>(Primitive::kPrimInt)),
       graph->GetDexFile(),
       kQuickAllocArray);
   block->AddInstruction(new_array);
@@ -692,7 +692,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -795,7 +795,7 @@
   graph_->AddBlock(entry);
   graph_->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HInstruction* constant_0 = graph_->GetIntConstant(0);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index a341086..8a6b94e 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -383,7 +383,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+    __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
                                                 : kQuickInitializeType;
     arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3953,7 +3953,7 @@
 
 void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
   // Note: if heap poisoning is enabled, the entry point takes cares
   // of poisoning the reference.
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5743,7 +5743,7 @@
 void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -5830,7 +5830,7 @@
                         current_method,
                         ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
       // /* GcRoot<mirror::Class> */ out = out[type_index]
-      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
       GenerateGcRootFieldLoad(cls, out_loc, out, offset, read_barrier_option);
       generate_null_check = !cls->IsInDexCache();
     }
@@ -7324,8 +7324,8 @@
 }
 
 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
-    const DexFile& dex_file, uint32_t type_index) {
-  return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+    const DexFile& dex_file, dex::TypeIndex type_index) {
+  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
 }
 
 CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
@@ -7347,7 +7347,7 @@
 }
 
 Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
-                                                           uint32_t type_index) {
+                                                           dex::TypeIndex type_index) {
   return boot_image_type_patches_.GetOrCreate(
       TypeReference(&dex_file, type_index),
       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -7452,7 +7452,7 @@
     uint32_t literal_offset = literal->GetLabel()->Position();
     linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
                                                      target_type.dex_file,
-                                                     target_type.type_index));
+                                                     target_type.type_index.index_));
   }
   EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
                                                               linker_patches);
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 8ace3da..a4ccb57 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -19,6 +19,7 @@
 
 #include "base/enums.h"
 #include "code_generator.h"
+#include "dex_file_types.h"
 #include "driver/compiler_options.h"
 #include "nodes.h"
 #include "string_reference.h"
@@ -481,11 +482,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
                                                        uint32_t element_offset);
   Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
-  Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+  Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
   Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
   Literal* DeduplicateDexCacheAddressLiteral(uint32_t address);
   Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, uint32_t string_index);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index c9e563b..59e1784 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -288,7 +288,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+    __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex().index_);
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
                                                 : kQuickInitializeType;
     arm64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -4102,9 +4102,9 @@
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(
     const DexFile& dex_file,
-    uint32_t type_index,
+    dex::TypeIndex type_index,
     vixl::aarch64::Label* adrp_label) {
-  return NewPcRelativePatch(dex_file, type_index, adrp_label, &pc_relative_type_patches_);
+  return NewPcRelativePatch(dex_file, type_index.index_, adrp_label, &pc_relative_type_patches_);
 }
 
 vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch(
@@ -4136,7 +4136,7 @@
 }
 
 vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateBootImageTypeLiteral(
-    const DexFile& dex_file, uint32_t type_index) {
+    const DexFile& dex_file, dex::TypeIndex type_index) {
   return boot_image_type_patches_.GetOrCreate(
       TypeReference(&dex_file, type_index),
       [this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
@@ -4257,7 +4257,7 @@
     vixl::aarch64::Literal<uint32_t>* literal = entry.second;
     linker_patches->push_back(LinkerPatch::TypePatch(literal->GetOffset(),
                                                      target_type.dex_file,
-                                                     target_type.type_index));
+                                                     target_type.type_index.index_));
   }
   EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
                                                                 linker_patches);
@@ -4381,7 +4381,7 @@
 
 void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -4417,7 +4417,7 @@
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
       // Add ADRP with its PC-relative type patch.
       const DexFile& dex_file = cls->GetDexFile();
-      uint32_t type_index = cls->GetTypeIndex();
+      dex::TypeIndex type_index = cls->GetTypeIndex();
       vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
       codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
       // Add ADD with its PC-relative type patch.
@@ -4485,7 +4485,7 @@
       GenerateGcRootFieldLoad(cls,
                               out_loc,
                               out.X(),
-                              CodeGenerator::GetCacheOffset(cls->GetTypeIndex()),
+                              CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_),
                               /* fixup_label */ nullptr,
                               read_barrier_option);
       generate_null_check = !cls->IsInDexCache();
@@ -4775,7 +4775,7 @@
   InvokeRuntimeCallingConvention calling_convention;
   Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
   DCHECK(type_index.Is(w0));
-  __ Mov(type_index, instruction->GetTypeIndex());
+  __ Mov(type_index, instruction->GetTypeIndex().index_);
   // Note: if heap poisoning is enabled, the entry point takes cares
   // of poisoning the reference.
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index a2ab607..1545fd3 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -20,6 +20,7 @@
 #include "arch/arm64/quick_method_frame_info_arm64.h"
 #include "code_generator.h"
 #include "common_arm64.h"
+#include "dex_file_types.h"
 #include "driver/compiler_options.h"
 #include "nodes.h"
 #include "parallel_move_resolver.h"
@@ -547,7 +548,7 @@
   // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
   // to the associated ADRP patch label).
   vixl::aarch64::Label* NewPcRelativeTypePatch(const DexFile& dex_file,
-                                               uint32_t type_index,
+                                               dex::TypeIndex type_index,
                                                vixl::aarch64::Label* adrp_label = nullptr);
 
   // Add a new PC-relative dex cache array patch for an instruction and return
@@ -562,7 +563,7 @@
   vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageStringLiteral(const DexFile& dex_file,
                                                                       uint32_t string_index);
   vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
-                                                                    uint32_t type_index);
+                                                                    dex::TypeIndex type_index);
   vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address);
   vixl::aarch64::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address);
   vixl::aarch64::Literal<uint32_t>* DeduplicateJitStringLiteral(const DexFile& dex_file,
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 61e6b4b..b8d9a91 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -398,7 +398,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConventionARMVIXL calling_convention;
-    __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+    __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
                                                 : kQuickInitializeType;
     arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3217,7 +3217,7 @@
 
 void InstructionCodeGeneratorARMVIXL::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConventionARMVIXL calling_convention;
-  __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
   // Note: if heap poisoning is enabled, the entry point takes cares
   // of poisoning the reference.
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -4968,7 +4968,7 @@
 void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -5000,7 +5000,7 @@
           ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value();
       GetAssembler()->LoadFromOffset(kLoadWord, out, current_method, resolved_types_offset);
       // /* GcRoot<mirror::Class> */ out = out[type_index]
-      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
       GenerateGcRootFieldLoad(cls, out_loc, out, offset, kEmitCompilerReadBarrier);
       generate_null_check = !cls->IsInDexCache();
       break;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index fcbb8f0..8f94834 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -224,7 +224,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+    __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
 
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
                                                 : kQuickInitializeType;
@@ -1056,7 +1056,7 @@
     uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
     linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
                                                      target_type.dex_file,
-                                                     target_type.type_index));
+                                                     target_type.type_index.index_));
   }
   for (const auto& entry : boot_image_address_patches_) {
     DCHECK(GetCompilerOptions().GetIncludePatchInformation());
@@ -1073,8 +1073,8 @@
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
-    const DexFile& dex_file, uint32_t type_index) {
-  return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+    const DexFile& dex_file, dex::TypeIndex type_index) {
+  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
@@ -1117,7 +1117,7 @@
 }
 
 Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
-                                                            uint32_t type_index) {
+                                                            dex::TypeIndex type_index) {
   return boot_image_type_patches_.GetOrCreate(
       TypeReference(&dex_file, type_index),
       [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -5539,7 +5539,7 @@
 void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -5633,7 +5633,7 @@
                         base_or_current_method_reg,
                         ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
       // /* GcRoot<mirror::Class> */ out = out[type_index]
-      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+      size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
       GenerateGcRootFieldLoad(cls, out_loc, out, offset);
       generate_null_check = !cls->IsInDexCache();
     }
@@ -5975,7 +5975,7 @@
   Register current_method_register = calling_convention.GetRegisterAt(2);
   __ Lw(current_method_register, SP, kCurrentMethodStackOffset);
   // Move an uint16_t value to a register.
-  __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+  __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
                        void*, uint32_t, int32_t, ArtMethod*>();
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index e132819..e225d20 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -449,11 +449,11 @@
   };
 
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
   PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
                                                        uint32_t element_offset);
   Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
-  Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+  Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
   Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
 
   void EmitPcRelativeAddressPlaceholder(PcRelativePatchInfo* info, Register out, Register base);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 1a54935..02b01c8 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -180,7 +180,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+    __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
                                                 : kQuickInitializeType;
     mips64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3157,7 +3157,7 @@
 void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -3174,7 +3174,7 @@
     __ LoadFromOffset(kLoadDoubleword, out, current_method,
                       ArtMethod::DexCacheResolvedTypesOffset(kMips64PointerSize).Int32Value());
     __ LoadFromOffset(
-        kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+        kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_));
     // TODO: We will need a read barrier here.
     if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
       DCHECK(cls->CanCallRuntime());
@@ -3382,7 +3382,8 @@
 void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) {
   LocationSummary* locations = instruction->GetLocations();
   // Move an uint16_t value to a register.
-  __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex());
+  __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(),
+                 instruction->GetTypeIndex().index_);
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
   CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
 }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3849437..51e902a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -265,7 +265,7 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
+    __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex().index_));
     x86_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage
                                           : kQuickInitializeType,
                                at_, dex_pc_, this);
@@ -4168,7 +4168,7 @@
 
 void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
-  __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
+  __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex().index_));
   // Note: if heap poisoning is enabled, the entry point takes cares
   // of poisoning the reference.
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -4612,7 +4612,7 @@
 }
 
 void CodeGeneratorX86::RecordTypePatch(HLoadClass* load_class) {
-  type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+  type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   __ Bind(&type_patches_.back().label);
 }
 
@@ -6060,7 +6060,7 @@
 void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -6142,7 +6142,8 @@
       // /* GcRoot<mirror::Class> */ out = out[type_index]
       GenerateGcRootFieldLoad(cls,
                               out_loc,
-                              Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+                              Address(out,
+                                      CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
                               /* fixup_label */ nullptr,
                               read_barrier_option);
       generate_null_check = !cls->IsInDexCache();
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 02f5491..3467313 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -246,7 +246,8 @@
     SaveLiveRegisters(codegen, locations);
 
     InvokeRuntimeCallingConvention calling_convention;
-    __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
+    __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
+            Immediate(cls_->GetTypeIndex().index_));
     x86_64_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage : kQuickInitializeType,
                                   at_,
                                   dex_pc_,
@@ -1110,7 +1111,7 @@
 }
 
 void CodeGeneratorX86_64::RecordTypePatch(HLoadClass* load_class) {
-  type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+  type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
   __ Bind(&type_patches_.back().label);
 }
 
@@ -4098,7 +4099,7 @@
 void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
   InvokeRuntimeCallingConvention calling_convention;
   codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
-                           instruction->GetTypeIndex());
+                           instruction->GetTypeIndex().index_);
   // Note: if heap poisoning is enabled, the entry point takes cares
   // of poisoning the reference.
   codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5485,7 +5486,7 @@
 void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
   LocationSummary* locations = cls->GetLocations();
   if (cls->NeedsAccessCheck()) {
-    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+    codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
     codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
     CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
     return;
@@ -5568,7 +5569,7 @@
       GenerateGcRootFieldLoad(
           cls,
           out_loc,
-          Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+          Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
           /* fixup_label */ nullptr,
           read_barrier_option);
       generate_null_check = !cls->IsInDexCache();
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 5fac3ac..7ef28ed 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -756,7 +756,7 @@
 
   // Make various unsigned comparisons with zero against a parameter.
   HInstruction* parameter = new (&allocator_) HParameterValue(
-      graph_->GetDexFile(), 0, 0, Primitive::kPrimInt, true);
+      graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt, true);
   entry_block->AddInstruction(parameter);
   entry_block->AddInstruction(new (&allocator_) HGoto());
 
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 6abf00e..437d35c 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -35,7 +35,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
-                                                             0,
+                                                             dex::TypeIndex(0),
                                                              0,
                                                              Primitive::kPrimNot);
   entry->AddInstruction(parameter);
@@ -120,7 +120,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
-                                                             0,
+                                                             dex::TypeIndex(0),
                                                              0,
                                                              Primitive::kPrimNot);
   entry->AddInstruction(parameter);
@@ -204,7 +204,7 @@
   graph->SetEntryBlock(entry);
 
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
-                                                             0,
+                                                             dex::TypeIndex(0),
                                                              0,
                                                              Primitive::kPrimNot);
   entry->AddInstruction(parameter);
@@ -352,7 +352,7 @@
   inner_loop_exit->AddSuccessor(outer_loop_header);
 
   HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
-                                                             0,
+                                                             dex::TypeIndex(0),
                                                              0,
                                                              Primitive::kPrimBoolean);
   entry->AddInstruction(parameter);
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 031f1d7..3425b88 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -80,7 +80,7 @@
 
     // Provide entry and exit instructions.
     parameter_ = new (&allocator_) HParameterValue(
-        graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
+        graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
     entry_->AddInstruction(parameter_);
     constant0_ = graph_->GetIntConstant(0);
     constant1_ = graph_->GetIntConstant(1);
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 8bbdd4a..4c99e3c 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -62,9 +62,15 @@
     graph_->SetEntryBlock(entry_block_);
     graph_->SetExitBlock(exit_block_);
     // Two parameters.
-    x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+    x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                           dex::TypeIndex(0),
+                                           0,
+                                           Primitive::kPrimInt);
     entry_block_->AddInstruction(x_);
-    y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+    y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                           dex::TypeIndex(0),
+                                           0,
+                                           Primitive::kPrimInt);
     entry_block_->AddInstruction(y_);
     // Set arbitrary range analysis hint while testing private methods.
     SetHint(x_);
@@ -572,7 +578,8 @@
   HInstruction* new_array = new (&allocator_)
       HNewArray(x_,
                 graph_->GetCurrentMethod(),
-                0, Primitive::kPrimInt,
+                0,
+                dex::TypeIndex(Primitive::kPrimInt),
                 graph_->GetDexFile(),
                 kQuickAllocArray);
   entry_block_->AddInstruction(new_array);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 7fe54b9..16a465a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -197,15 +197,15 @@
   }
 }
 
-static uint32_t FindClassIndexIn(mirror::Class* cls,
-                                 const DexFile& dex_file,
-                                 Handle<mirror::DexCache> dex_cache)
+static dex::TypeIndex FindClassIndexIn(mirror::Class* cls,
+                                       const DexFile& dex_file,
+                                       Handle<mirror::DexCache> dex_cache)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  uint32_t index = DexFile::kDexNoIndex;
+  dex::TypeIndex index;
   if (cls->GetDexCache() == nullptr) {
     DCHECK(cls->IsArrayClass()) << cls->PrettyClass();
     index = cls->FindTypeIndexInOtherDexFile(dex_file);
-  } else if (cls->GetDexTypeIndex() == DexFile::kDexNoIndex16) {
+  } else if (!cls->GetDexTypeIndex().IsValid()) {
     DCHECK(cls->IsProxyClass()) << cls->PrettyClass();
     // TODO: deal with proxy classes.
   } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) {
@@ -223,8 +223,8 @@
     // We cannot guarantee the entry in the dex cache will resolve to the same class,
     // as there may be different class loaders. So only return the index if it's
     // the right class in the dex cache already.
-    if (index != DexFile::kDexNoIndex && dex_cache->GetResolvedType(index) != cls) {
-      index = DexFile::kDexNoIndex;
+    if (index.IsValid() && dex_cache->GetResolvedType(index) != cls) {
+      index = dex::TypeIndex::Invalid();
     }
   }
 
@@ -363,9 +363,9 @@
       << invoke_instruction->DebugName();
 
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
-  uint32_t class_index = FindClassIndexIn(
+  dex::TypeIndex class_index = FindClassIndexIn(
       ic.GetMonomorphicType(), caller_dex_file, caller_compilation_unit_.GetDexCache());
-  if (class_index == DexFile::kDexNoIndex) {
+  if (!class_index.IsValid()) {
     VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method)
                    << " from inline cache is not inlined because its class is not"
                    << " accessible to the caller";
@@ -417,7 +417,7 @@
 HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
                                      HInstruction* cursor,
                                      HBasicBlock* bb_cursor,
-                                     uint32_t class_index,
+                                     dex::TypeIndex class_index,
                                      bool is_referrer,
                                      HInstruction* invoke_instruction,
                                      bool with_deoptimization) {
@@ -489,10 +489,10 @@
     HInstruction* cursor = invoke_instruction->GetPrevious();
     HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
 
-    uint32_t class_index = FindClassIndexIn(
+    dex::TypeIndex class_index = FindClassIndexIn(
         ic.GetTypeAt(i), caller_dex_file, caller_compilation_unit_.GetDexCache());
     HInstruction* return_replacement = nullptr;
-    if (class_index == DexFile::kDexNoIndex ||
+    if (!class_index.IsValid() ||
         !TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
       all_targets_inlined = false;
     } else {
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index a1dcd58..682393e 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -17,6 +17,7 @@
 #ifndef ART_COMPILER_OPTIMIZING_INLINER_H_
 #define ART_COMPILER_OPTIMIZING_INLINER_H_
 
+#include "dex_file_types.h"
 #include "invoke_type.h"
 #include "optimization.h"
 
@@ -150,7 +151,7 @@
   HInstruction* AddTypeGuard(HInstruction* receiver,
                              HInstruction* cursor,
                              HBasicBlock* bb_cursor,
-                             uint32_t class_index,
+                             dex::TypeIndex class_index,
                              bool is_referrer,
                              HInstruction* invoke_instruction,
                              bool with_deoptimization)
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index b44137d..40de5ce 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -908,7 +908,7 @@
                       false /* is_unresolved */);
 }
 
-bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) {
+bool HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc) {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1004,7 +1004,7 @@
   Handle<mirror::Class> resolved_method_class(hs.NewHandle(resolved_method->GetDeclaringClass()));
 
   // The index at which the method's class is stored in the DexCache's type array.
-  uint32_t storage_index = DexFile::kDexNoIndex;
+  dex::TypeIndex storage_index;
   bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
   if (is_outer_class) {
     storage_index = outer_class->GetDexTypeIndex();
@@ -1021,7 +1021,7 @@
 
   if (IsInitialized(resolved_method_class)) {
     *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
-  } else if (storage_index != DexFile::kDexNoIndex) {
+  } else if (storage_index.IsValid()) {
     *clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
     HLoadClass* load_class = new (arena_) HLoadClass(
         graph_->GetCurrentMethod(),
@@ -1297,7 +1297,7 @@
   return GetClassFrom(compiler_driver_, *dex_compilation_unit_);
 }
 
-bool HInstructionBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
+bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<3> hs(soa.Self());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1360,7 +1360,7 @@
   Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
 
   // The index at which the field's class is stored in the DexCache's type array.
-  uint32_t storage_index;
+  dex::TypeIndex storage_index;
   bool is_outer_class = (outer_class.Get() == resolved_field->GetDeclaringClass());
   if (is_outer_class) {
     storage_index = outer_class->GetDexTypeIndex();
@@ -1497,7 +1497,7 @@
 }
 
 void HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc,
-                                              uint32_t type_index,
+                                              dex::TypeIndex type_index,
                                               uint32_t number_of_vreg_arguments,
                                               bool is_range,
                                               uint32_t* args,
@@ -1644,7 +1644,7 @@
 void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
                                          uint8_t destination,
                                          uint8_t reference,
-                                         uint16_t type_index,
+                                         dex::TypeIndex type_index,
                                          uint32_t dex_pc) {
   ScopedObjectAccess soa(Thread::Current());
   StackHandleScope<1> hs(soa.Self());
@@ -1684,14 +1684,14 @@
   }
 }
 
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index,
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index,
                                            Handle<mirror::DexCache> dex_cache,
                                            bool* finalizable) const {
   return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks(
       dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index, finalizable);
 }
 
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index, bool* finalizable) const {
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const {
   ScopedObjectAccess soa(Thread::Current());
   Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
   return NeedsAccessCheck(type_index, dex_cache, finalizable);
@@ -2449,7 +2449,7 @@
     }
 
     case Instruction::NEW_INSTANCE: {
-      if (!BuildNewInstance(instruction.VRegB_21c(), dex_pc)) {
+      if (!BuildNewInstance(dex::TypeIndex(instruction.VRegB_21c()), dex_pc)) {
         return false;
       }
       UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
@@ -2457,7 +2457,7 @@
     }
 
     case Instruction::NEW_ARRAY: {
-      uint16_t type_index = instruction.VRegC_22c();
+      dex::TypeIndex type_index(instruction.VRegC_22c());
       HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
       bool finalizable;
       QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index, &finalizable)
@@ -2475,7 +2475,7 @@
 
     case Instruction::FILLED_NEW_ARRAY: {
       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
-      uint32_t type_index = instruction.VRegB_35c();
+      dex::TypeIndex type_index(instruction.VRegB_35c());
       uint32_t args[5];
       instruction.GetVarArgs(args);
       BuildFilledNewArray(dex_pc, type_index, number_of_vreg_arguments, false, args, 0);
@@ -2484,7 +2484,7 @@
 
     case Instruction::FILLED_NEW_ARRAY_RANGE: {
       uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
-      uint32_t type_index = instruction.VRegB_3rc();
+      dex::TypeIndex type_index(instruction.VRegB_3rc());
       uint32_t register_index = instruction.VRegC_3rc();
       BuildFilledNewArray(
           dex_pc, type_index, number_of_vreg_arguments, true, nullptr, register_index);
@@ -2641,7 +2641,7 @@
     }
 
     case Instruction::CONST_CLASS: {
-      uint16_t type_index = instruction.VRegB_21c();
+      dex::TypeIndex type_index(instruction.VRegB_21c());
       // `CanAccessTypeWithoutChecks` will tell whether the method being
       // built is trying to access its own class, so that the generated
       // code can optimize for this case. However, the optimization does not
@@ -2682,14 +2682,14 @@
     case Instruction::INSTANCE_OF: {
       uint8_t destination = instruction.VRegA_22c();
       uint8_t reference = instruction.VRegB_22c();
-      uint16_t type_index = instruction.VRegC_22c();
+      dex::TypeIndex type_index(instruction.VRegC_22c());
       BuildTypeCheck(instruction, destination, reference, type_index, dex_pc);
       break;
     }
 
     case Instruction::CHECK_CAST: {
       uint8_t reference = instruction.VRegA_21c();
-      uint16_t type_index = instruction.VRegB_21c();
+      dex::TypeIndex type_index(instruction.VRegB_21c());
       BuildTypeCheck(instruction, -1, reference, type_index, dex_pc);
       break;
     }
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index aa34ddd..f29e522 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -20,6 +20,7 @@
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
 #include "block_builder.h"
+#include "dex_file_types.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_driver-inl.h"
 #include "driver/dex_compilation_unit.h"
@@ -100,11 +101,11 @@
 
   // Returns whether the current method needs access check for the type.
   // Output parameter finalizable is set to whether the type is finalizable.
-  bool NeedsAccessCheck(uint32_t type_index,
+  bool NeedsAccessCheck(dex::TypeIndex type_index,
                         Handle<mirror::DexCache> dex_cache,
                         /*out*/bool* finalizable) const
       REQUIRES_SHARED(Locks::mutator_lock_);
-  bool NeedsAccessCheck(uint32_t type_index, /*out*/bool* finalizable) const;
+  bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const;
 
   template<typename T>
   void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
@@ -176,7 +177,7 @@
 
   // Builds a new array node and the instructions that fill it.
   void BuildFilledNewArray(uint32_t dex_pc,
-                           uint32_t type_index,
+                           dex::TypeIndex type_index,
                            uint32_t number_of_vreg_arguments,
                            bool is_range,
                            uint32_t* args,
@@ -205,7 +206,7 @@
   void BuildTypeCheck(const Instruction& instruction,
                       uint8_t destination,
                       uint8_t reference,
-                      uint16_t type_index,
+                      dex::TypeIndex type_index,
                       uint32_t dex_pc);
 
   // Builds an instruction sequence for a switch statement.
@@ -218,7 +219,7 @@
   mirror::Class* GetCompilingClass() const;
 
   // Returns whether `type_index` points to the outer-most compiling method's class.
-  bool IsOutermostCompilingClass(uint16_t type_index) const;
+  bool IsOutermostCompilingClass(dex::TypeIndex type_index) const;
 
   void PotentiallySimplifyFakeString(uint16_t original_dex_register,
                                      uint32_t dex_pc,
@@ -258,7 +259,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Build a HNewInstance instruction.
-  bool BuildNewInstance(uint16_t type_index, uint32_t dex_pc);
+  bool BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc);
 
   // Return whether the compiler can assume `cls` is initialized.
   bool IsInitialized(Handle<mirror::Class> cls) const
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 2a62643..8c34dc6 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -63,7 +63,10 @@
     return_->AddSuccessor(exit_);
 
     // Provide boiler-plate instructions.
-    parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+    parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                   dex::TypeIndex(0),
+                                                   0,
+                                                   Primitive::kPrimNot);
     entry_->AddInstruction(parameter_);
     int_constant_ = graph_->GetIntConstant(42);
     float_constant_ = graph_->GetFloatConstant(42.0f);
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 7805a69..9a6b493 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -48,7 +48,10 @@
     graph_->AddBlock(exit_block_);
     graph_->SetEntryBlock(entry_block_);
     graph_->SetExitBlock(exit_block_);
-    parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+    parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                   dex::TypeIndex(0),
+                                                   0,
+                                                   Primitive::kPrimInt);
     entry_block_->AddInstruction(parameter_);
     return_block_->AddInstruction(new (&allocator_) HReturnVoid());
     exit_block_->AddInstruction(new (&allocator_) HExit());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 215ed54..eebc49c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -29,6 +29,7 @@
 #include "base/stl_util.h"
 #include "base/transform_array_ref.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "handle.h"
 #include "handle_scope.h"
@@ -800,7 +801,7 @@
   }
 
   // Catch block information constructor.
-  TryCatchInformation(uint16_t catch_type_index, const DexFile& dex_file)
+  TryCatchInformation(dex::TypeIndex catch_type_index, const DexFile& dex_file)
       : try_entry_(nullptr),
         catch_dex_file_(&dex_file),
         catch_type_index_(catch_type_index) {}
@@ -816,10 +817,10 @@
 
   bool IsCatchAllTypeIndex() const {
     DCHECK(IsCatchBlock());
-    return catch_type_index_ == DexFile::kDexNoIndex16;
+    return !catch_type_index_.IsValid();
   }
 
-  uint16_t GetCatchTypeIndex() const {
+  dex::TypeIndex GetCatchTypeIndex() const {
     DCHECK(IsCatchBlock());
     return catch_type_index_;
   }
@@ -836,7 +837,7 @@
 
   // Exception type information. Only set for catch blocks.
   const DexFile* catch_dex_file_;
-  const uint16_t catch_type_index_;
+  const dex::TypeIndex catch_type_index_;
 };
 
 static constexpr size_t kNoLifetime = -1;
@@ -3671,7 +3672,7 @@
   HNewInstance(HInstruction* cls,
                HCurrentMethod* current_method,
                uint32_t dex_pc,
-               uint16_t type_index,
+               dex::TypeIndex type_index,
                const DexFile& dex_file,
                bool needs_access_check,
                bool finalizable,
@@ -3686,7 +3687,7 @@
     SetRawInputAt(1, current_method);
   }
 
-  uint16_t GetTypeIndex() const { return type_index_; }
+  dex::TypeIndex GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
   // Calls runtime so needs an environment.
@@ -3719,7 +3720,7 @@
   static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
                 "Too many packed fields.");
 
-  const uint16_t type_index_;
+  const dex::TypeIndex type_index_;
   const DexFile& dex_file_;
   QuickEntrypointEnum entrypoint_;
 
@@ -4265,7 +4266,7 @@
   HNewArray(HInstruction* length,
             HCurrentMethod* current_method,
             uint32_t dex_pc,
-            uint16_t type_index,
+            dex::TypeIndex type_index,
             const DexFile& dex_file,
             QuickEntrypointEnum entrypoint)
       : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
@@ -4276,7 +4277,7 @@
     SetRawInputAt(1, current_method);
   }
 
-  uint16_t GetTypeIndex() const { return type_index_; }
+  dex::TypeIndex GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
   // Calls runtime so needs an environment.
@@ -4292,7 +4293,7 @@
   DECLARE_INSTRUCTION(NewArray);
 
  private:
-  const uint16_t type_index_;
+  const dex::TypeIndex type_index_;
   const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
 
@@ -4829,7 +4830,7 @@
 class HParameterValue FINAL : public HExpression<0> {
  public:
   HParameterValue(const DexFile& dex_file,
-                  uint16_t type_index,
+                  dex::TypeIndex type_index,
                   uint8_t index,
                   Primitive::Type parameter_type,
                   bool is_this = false)
@@ -4842,7 +4843,7 @@
   }
 
   const DexFile& GetDexFile() const { return dex_file_; }
-  uint16_t GetTypeIndex() const { return type_index_; }
+  dex::TypeIndex GetTypeIndex() const { return type_index_; }
   uint8_t GetIndex() const { return index_; }
   bool IsThis() const { return GetPackedFlag<kFlagIsThis>(); }
 
@@ -4860,7 +4861,7 @@
                 "Too many packed fields.");
 
   const DexFile& dex_file_;
-  const uint16_t type_index_;
+  const dex::TypeIndex type_index_;
   // The index of this parameter in the parameters list. Must be less
   // than HGraph::number_of_in_vregs_.
   const uint8_t index_;
@@ -5455,7 +5456,7 @@
   };
 
   HLoadClass(HCurrentMethod* current_method,
-             uint16_t type_index,
+             dex::TypeIndex type_index,
              const DexFile& dex_file,
              bool is_referrers_class,
              uint32_t dex_pc,
@@ -5487,7 +5488,7 @@
 
   void SetLoadKindWithTypeReference(LoadKind load_kind,
                                     const DexFile& dex_file,
-                                    uint32_t type_index) {
+                                    dex::TypeIndex type_index) {
     DCHECK(HasTypeReference(load_kind));
     DCHECK(IsSameDexFile(dex_file_, dex_file));
     DCHECK_EQ(type_index_, type_index);
@@ -5511,7 +5512,7 @@
 
   bool InstructionDataEquals(const HInstruction* other) const;
 
-  size_t ComputeHashCode() const OVERRIDE { return type_index_; }
+  size_t ComputeHashCode() const OVERRIDE { return type_index_.index_; }
 
   bool CanBeNull() const OVERRIDE { return false; }
 
@@ -5547,7 +5548,7 @@
     loaded_class_rti_ = rti;
   }
 
-  uint32_t GetTypeIndex() const { return type_index_; }
+  dex::TypeIndex GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
   uint32_t GetDexCacheElementOffset() const;
@@ -5630,7 +5631,7 @@
   // for PC-relative loads, i.e. kDexCachePcRelative or kBootImageLinkTimePcRelative.
   HUserRecord<HInstruction*> special_input_;
 
-  const uint16_t type_index_;
+  const dex::TypeIndex type_index_;
   const DexFile& dex_file_;
 
   union {
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index d4e2a58..5d9a652 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -35,7 +35,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
   entry->AddInstruction(new (&allocator) HGoto());
 
@@ -78,9 +78,9 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   HInstruction* parameter2 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(parameter2);
   entry->AddInstruction(new (&allocator) HExit());
@@ -106,7 +106,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   ASSERT_FALSE(parameter->HasUses());
@@ -127,7 +127,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter1 = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   HInstruction* with_environment = new (&allocator) HNullCheck(parameter1, 0);
   entry->AddInstruction(parameter1);
   entry->AddInstruction(with_environment);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 85519c9..604d99c 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -61,6 +61,7 @@
 #include "debug/method_debug_info.h"
 #include "dex/verification_results.h"
 #include "dex/verified_method.h"
+#include "dex_file_types.h"
 #include "driver/compiler_driver-inl.h"
 #include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
@@ -948,7 +949,7 @@
     graph->SetArtMethod(method);
     ScopedObjectAccess soa(Thread::Current());
     interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize());
-    uint16_t type_index = method->GetDeclaringClass()->GetDexTypeIndex();
+    dex::TypeIndex type_index = method->GetDeclaringClass()->GetDexTypeIndex();
 
     // Update the dex cache if the type is not in it yet. Note that under AOT,
     // the verifier must have set it, but under JIT, there's no guarantee, as we
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 0db6088..f9ac3a0 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -143,7 +143,7 @@
   // - or the load class has only one use.
   if (instruction->IsFinalizable() || has_only_one_use || load_class->NeedsAccessCheck()) {
     instruction->SetEntrypoint(kQuickAllocObject);
-    instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex()), 0);
+    instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex().index_), 0);
     if (has_only_one_use) {
       // We've just removed the only use of the HLoadClass. Since we don't run DCE after this pass,
       // do it manually if possible.
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d588dea..c191c66 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -96,7 +96,7 @@
   void VisitBoundType(HBoundType* instr) OVERRIDE;
   void VisitNullCheck(HNullCheck* instr) OVERRIDE;
   void UpdateReferenceTypeInfo(HInstruction* instr,
-                               uint16_t type_idx,
+                               dex::TypeIndex type_idx,
                                const DexFile& dex_file,
                                bool is_exact);
 
@@ -463,7 +463,7 @@
 }
 
 void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
-                                                                   uint16_t type_idx,
+                                                                   dex::TypeIndex type_idx,
                                                                    const DexFile& dex_file,
                                                                    bool is_exact) {
   DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
@@ -484,7 +484,7 @@
 
 static mirror::Class* GetClassFromDexCache(Thread* self,
                                            const DexFile& dex_file,
-                                           uint16_t type_idx,
+                                           dex::TypeIndex type_idx,
                                            Handle<mirror::DexCache> hint_dex_cache)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 55ea99e..559f409 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -20,6 +20,7 @@
 #include "code_generator.h"
 #include "code_generator_x86.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "dex_instruction.h"
 #include "driver/compiler_options.h"
 #include "nodes.h"
@@ -495,7 +496,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -658,7 +659,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
   entry->AddInstruction(parameter);
 
   HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -742,7 +743,7 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* parameter = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   entry->AddInstruction(parameter);
 
   HInstruction* constant1 = graph->GetIntConstant(1);
@@ -821,9 +822,9 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* first = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   HInstruction* second = new (allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   entry->AddInstruction(first);
   entry->AddInstruction(second);
 
@@ -883,13 +884,13 @@
   graph->AddBlock(entry);
   graph->SetEntryBlock(entry);
   HInstruction* one = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   HInstruction* two = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   HInstruction* three = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   HInstruction* four = new (&allocator) HParameterValue(
-      graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+      graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
   entry->AddInstruction(one);
   entry->AddInstruction(two);
   entry->AddInstruction(three);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 15254ed..a127708 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -147,7 +147,7 @@
   DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
 
   const DexFile& dex_file = load_class->GetDexFile();
-  uint32_t type_index = load_class->GetTypeIndex();
+  dex::TypeIndex type_index = load_class->GetTypeIndex();
 
   bool is_in_dex_cache = false;
   bool is_in_boot_image = false;
@@ -197,7 +197,7 @@
           // inlined frames are used correctly for OOM stack trace.
           // TODO: Write a test for this. Bug: 29416588
           desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
-          void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index];
+          void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index.index_];
           address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
         }
         // AOT app compilation. Check if the class is in the boot image.
diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc
index da4ac79..922f8b1 100644
--- a/compiler/utils/test_dex_file_builder_test.cc
+++ b/compiler/utils/test_dex_file_builder_test.cc
@@ -62,7 +62,8 @@
   };
   ASSERT_EQ(arraysize(expected_types), dex_file->NumTypeIds());
   for (size_t i = 0; i != arraysize(expected_types); ++i) {
-    EXPECT_STREQ(expected_types[i], dex_file->GetTypeDescriptor(dex_file->GetTypeId(i))) << i;
+    EXPECT_STREQ(expected_types[i],
+                 dex_file->GetTypeDescriptor(dex_file->GetTypeId(dex::TypeIndex(i)))) << i;
   }
 
   ASSERT_EQ(1u, dex_file->NumFieldIds());
diff --git a/compiler/utils/type_reference.h b/compiler/utils/type_reference.h
index d0c1656..a0fa1a4 100644
--- a/compiler/utils/type_reference.h
+++ b/compiler/utils/type_reference.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 
 #include "base/logging.h"
+#include "dex_file_types.h"
 #include "string_reference.h"
 
 namespace art {
@@ -28,10 +29,10 @@
 
 // A type is located by its DexFile and the string_ids_ table index into that DexFile.
 struct TypeReference {
-  TypeReference(const DexFile* file, uint32_t index) : dex_file(file), type_index(index) { }
+  TypeReference(const DexFile* file, dex::TypeIndex index) : dex_file(file), type_index(index) { }
 
   const DexFile* dex_file;
-  uint32_t type_index;
+  dex::TypeIndex type_index;
 };
 
 // Compare the actual referenced type names. Used for type reference deduplication.
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 6b690aa..03d3f4e 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -23,6 +23,7 @@
 #include "compiler/driver/compiler_driver.h"
 #include "compiler_callbacks.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "handle_scope-inl.h"
 #include "verifier/method_verifier-inl.h"
 #include "mirror/class_loader.h"
@@ -207,8 +208,8 @@
         hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
     MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
     for (const DexFile* dex_file : dex_files_) {
-      const std::vector<uint16_t>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
-      std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+      const std::vector<dex::TypeIndex>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
+      std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
       for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
         const char* descriptor = dex_file->GetClassDescriptor(class_def);
@@ -228,10 +229,10 @@
   bool HasUnverifiedClass(const std::string& cls) {
     const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
     DCHECK(type_id != nullptr);
-    uint16_t index = primary_dex_file_->GetIndexForTypeId(*type_id);
+    dex::TypeIndex index = primary_dex_file_->GetIndexForTypeId(*type_id);
     MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
     for (const auto& dex_dep : verifier_deps_->dex_deps_) {
-      for (uint16_t entry : dex_dep.second->unverified_classes_) {
+      for (dex::TypeIndex entry : dex_dep.second->unverified_classes_) {
         if (index == entry) {
           return true;
         }
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 30de28e..03d6227 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -45,6 +45,7 @@
 #include "base/stringprintf.h"
 #include "dexdump_cfg.h"
 #include "dex_file-inl.h"
+#include "dex_file_types.h"
 #include "dex_instruction-inl.h"
 
 namespace art {
@@ -482,7 +483,7 @@
     }
     case DexFile::kDexAnnotationType: {
       const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
-      fputs(pDexFile->StringByTypeIdx(str_idx), gOutFile);
+      fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
       break;
     }
     case DexFile::kDexAnnotationField:
@@ -511,7 +512,7 @@
     }
     case DexFile::kDexAnnotationAnnotation: {
       const u4 type_idx = DecodeUnsignedLeb128(data);
-      fputs(pDexFile->StringByTypeIdx(type_idx), gOutFile);
+      fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
       // Decode and display all name=value pairs.
       const u4 size = DecodeUnsignedLeb128(data);
       for (u4 i = 0; i < size; i++) {
@@ -592,10 +593,10 @@
   // General class information.
   const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
   fprintf(gOutFile, "Class #%d header:\n", idx);
-  fprintf(gOutFile, "class_idx           : %d\n", pClassDef.class_idx_);
+  fprintf(gOutFile, "class_idx           : %d\n", pClassDef.class_idx_.index_);
   fprintf(gOutFile, "access_flags        : %d (0x%04x)\n",
           pClassDef.access_flags_, pClassDef.access_flags_);
-  fprintf(gOutFile, "superclass_idx      : %d\n", pClassDef.superclass_idx_);
+  fprintf(gOutFile, "superclass_idx      : %d\n", pClassDef.superclass_idx_.index_);
   fprintf(gOutFile, "interfaces_off      : %d (0x%06x)\n",
           pClassDef.interfaces_off_, pClassDef.interfaces_off_);
   fprintf(gOutFile, "source_file_idx     : %d\n", pClassDef.source_file_idx_);
@@ -747,9 +748,8 @@
     const u4 end = start + pTry->insn_count_;
     fprintf(gOutFile, "        0x%04x - 0x%04x\n", start, end);
     for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
-      const u2 tidx = it.GetHandlerTypeIndex();
-      const char* descriptor =
-          (tidx == DexFile::kDexNoIndex16) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
+      const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
+      const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
       fprintf(gOutFile, "          %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
     }  // for
   }  // for
@@ -834,7 +834,7 @@
       break;
     case Instruction::kIndexTypeRef:
       if (index < pDexFile->GetHeader().type_ids_size_) {
-        const char* tp = pDexFile->StringByTypeIdx(index);
+        const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
         outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
       } else {
         outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
@@ -1461,7 +1461,7 @@
   // General class information.
   char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
   const char* superclassDescriptor;
-  if (pClassDef.superclass_idx_ == DexFile::kDexNoIndex16) {
+  if (!pClassDef.superclass_idx_.IsValid()) {
     superclassDescriptor = nullptr;
   } else {
     superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index c3c763f..67f3e09 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -319,7 +319,7 @@
 }
 
 void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
-  const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
+  const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
   TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_));
   type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
 }
@@ -330,22 +330,22 @@
   TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
 
   ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_),
-                                  GetTypeId(disk_proto_id.return_type_idx_),
+                                  GetTypeId(disk_proto_id.return_type_idx_.index_),
                                   parameter_type_list);
   proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
 }
 
 void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
   const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
-  FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_),
-                                  GetTypeId(disk_field_id.type_idx_),
+  FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
+                                  GetTypeId(disk_field_id.type_idx_.index_),
                                   GetStringId(disk_field_id.name_idx_));
   field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
 }
 
 void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
   const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
-  MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_),
+  MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
                                      GetProtoId(disk_method_id.proto_idx_),
                                      GetStringId(disk_method_id.name_idx_));
   method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
@@ -353,9 +353,9 @@
 
 void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
   const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
-  const TypeId* class_type = GetTypeId(disk_class_def.class_idx_);
+  const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
   uint32_t access_flags = disk_class_def.access_flags_;
-  const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
+  const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
 
   const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
   TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
@@ -393,7 +393,7 @@
   TypeIdVector* type_vector = new TypeIdVector();
   uint32_t size = dex_type_list->Size();
   for (uint32_t index = 0; index < size; ++index) {
-    type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_));
+    type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
   }
   TypeList* new_type_list = new TypeList(type_vector);
   type_lists_.AddItem(new_type_list, offset);
@@ -597,8 +597,8 @@
         bool catch_all = false;
         TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
         for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
-          const uint16_t type_index = it.GetHandlerTypeIndex();
-          const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
+          const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
+          const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
           catch_all |= type_id == nullptr;
           addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
               new TypeAddrPair(type_id, it.GetHandlerAddress())));
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index 7c55659..05ad98f 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -350,7 +350,7 @@
   const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
   for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
     dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
-    uint16_t type_idx = class_def->ClassType()->GetIndex();
+    dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
     if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
       continue;
     }
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4c01c14..3ad0f1e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -794,7 +794,7 @@
       uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
       os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
-                         class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
+                         class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
          << " (" << oat_class.GetStatus() << ")"
          << " (" << oat_class.GetType() << ")\n";
       // TODO: include bitmap here if type is kOatClassSomeCompiled?
diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index cd0aa6f..776c31a 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -42,7 +42,7 @@
       ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
     }
     for (uint16_t i = 0; i < number_of_classes; i++) {
-      ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
+      ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
     }
 
     ASSERT_TRUE(info->Save(GetFd(profile)));
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index bbf9a8b..6665897 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1063,7 +1063,7 @@
   EXPECT_FALSE(self->IsExceptionPending());
   {
     // Use an arbitrary method from c to use as referrer
-    size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
+    size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex().index_),    // type_idx
                             // arbitrary
                             reinterpret_cast<size_t>(c->GetVirtualMethod(0, kRuntimePointerSize)),
                             0U,
@@ -1197,7 +1197,7 @@
   if ((false)) {
     // Use an arbitrary method from c to use as referrer
     size_t result = Invoke3(
-        static_cast<size_t>(c->GetDexTypeIndex()),    // type_idx
+        static_cast<size_t>(c->GetDexTypeIndex().index_),    // type_idx
         10U,
         // arbitrary
         reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0, kRuntimePointerSize)),
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index b46b058..25b8ed2 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -48,7 +48,7 @@
   return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
 }
 
-ObjPtr<mirror::Class> ArtField::ResolveGetType(uint32_t type_idx) {
+ObjPtr<mirror::Class> ArtField::ResolveGetType(dex::TypeIndex type_idx) {
   return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
 }
 
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 7c2f490..cacb324 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -19,6 +19,7 @@
 
 #include <jni.h>
 
+#include "dex_file_types.h"
 #include "gc_root.h"
 #include "modifiers.h"
 #include "obj_ptr.h"
@@ -216,7 +217,8 @@
  private:
   ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  ObjPtr<mirror::Class> ResolveGetType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  ObjPtr<mirror::Class> ResolveGetType(dex::TypeIndex type_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
   ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
                                               const DexFile& dex_file,
                                               uint32_t string_idx,
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index a652178..2dfdc16 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -183,17 +183,17 @@
 }
 
 template <bool kWithCheck>
-inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index,
+inline mirror::Class* ArtMethod::GetDexCacheResolvedType(dex::TypeIndex type_index,
                                                          PointerSize pointer_size) {
   if (kWithCheck) {
     mirror::DexCache* dex_cache =
         GetInterfaceMethodIfProxy(pointer_size)->GetDeclaringClass()->GetDexCache();
-    if (UNLIKELY(type_index >= dex_cache->NumResolvedTypes())) {
-      ThrowArrayIndexOutOfBoundsException(type_index, dex_cache->NumResolvedTypes());
+    if (UNLIKELY(type_index.index_ >= dex_cache->NumResolvedTypes())) {
+      ThrowArrayIndexOutOfBoundsException(type_index.index_, dex_cache->NumResolvedTypes());
       return nullptr;
     }
   }
-  mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index].Read();
+  mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index.index_].Read();
   return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
 }
 
@@ -210,7 +210,7 @@
   return GetDexCacheResolvedTypes(pointer_size) == other->GetDexCacheResolvedTypes(pointer_size);
 }
 
-inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx,
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx,
                                                        bool resolve,
                                                        PointerSize pointer_size) {
   mirror::Class* type = GetDexCacheResolvedType(type_idx, pointer_size);
@@ -336,7 +336,7 @@
   return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
 }
 
-inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size) {
+inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size) {
   DCHECK(!IsProxyMethod());
   return GetDexCacheResolvedType(type_idx, pointer_size) != nullptr;
 }
@@ -383,11 +383,10 @@
   const DexFile* dex_file = GetDexFile();
   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
-  uint16_t return_type_idx = proto_id.return_type_idx_;
-  return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
+  return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
 }
 
-inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
+inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
   DCHECK(!IsProxyMethod());
   const DexFile* dex_file = GetDexFile();
   return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
@@ -440,7 +439,7 @@
   const DexFile* dex_file = GetDexFile();
   const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
-  uint16_t return_type_idx = proto_id.return_type_idx_;
+  dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
   mirror::Class* type = GetDexCacheResolvedType(return_type_idx, pointer_size);
   if (type == nullptr && resolve) {
     type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index c550a1b..d1454b6 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -199,9 +199,9 @@
   // Iterate over the catch handlers associated with dex_pc.
   PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
   for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
-    uint16_t iter_type_idx = it.GetHandlerTypeIndex();
+    dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
     // Catch all case
-    if (iter_type_idx == DexFile::kDexNoIndex16) {
+    if (!iter_type_idx.IsValid()) {
       found_dex_pc = it.GetHandlerAddress();
       break;
     }
@@ -476,7 +476,11 @@
     }
     // The table is in the .vdex file.
     const OatFile::OatDexFile* oat_dex_file = GetDexCache()->GetDexFile()->GetOatDexFile();
-    return oat_dex_file->GetOatFile()->DexBegin() + header->vmap_table_offset_;
+    const OatFile* oat_file = oat_dex_file->GetOatFile();
+    if (oat_file == nullptr) {
+      return nullptr;
+    }
+    return oat_file->DexBegin() + header->vmap_table_offset_;
   } else {
     return oat_method.GetVmapTable();
   }
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b31999f..0e1d7e7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -343,7 +343,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <bool kWithCheck = true>
-  mirror::Class* GetDexCacheResolvedType(uint32_t type_idx, PointerSize pointer_size)
+  mirror::Class* GetDexCacheResolvedType(dex::TypeIndex type_idx, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
   void SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_cache_types,
                                 PointerSize pointer_size)
@@ -355,7 +355,9 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Get the Class* from the type index into this method's dex cache.
-  mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve, PointerSize pointer_size)
+  mirror::Class* GetClassFromTypeIndex(dex::TypeIndex type_idx,
+                                       bool resolve,
+                                       PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns true if this method has the same name and signature of the other method.
@@ -527,7 +529,7 @@
 
   const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  bool IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size)
+  bool IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   int32_t GetLineNumFromDexPC(uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -544,7 +546,7 @@
 
   const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
+  const char* GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 7359243..81adaeb 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -86,7 +86,7 @@
   return string.Ptr();
 }
 
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) {
   Thread::PoisonObjectPointersIfDebug();
   ObjPtr<mirror::Class> resolved_type =
       referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
@@ -103,7 +103,7 @@
   return resolved_type.Ptr();
 }
 
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtField* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) {
   Thread::PoisonObjectPointersIfDebug();
   ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
   ObjPtr<mirror::DexCache> dex_cache_ptr = declaring_class->GetDexCache();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4905514..0fdf4e1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -240,6 +240,12 @@
   ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
   CHECK(cause.get() != nullptr);
 
+  // Boot classpath classes should not fail initialization.
+  if (!Runtime::Current()->IsAotCompiler()) {
+    std::string tmp;
+    CHECK(klass->GetClassLoader() != nullptr) << klass->GetDescriptor(&tmp);
+  }
+
   env->ExceptionClear();
   bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error);
   env->Throw(cause.get());
@@ -730,10 +736,12 @@
     const DexFile& dex_file = java_lang_Object->GetDexFile();
     const DexFile::TypeId* void_type_id = dex_file.FindTypeId("V");
     CHECK(void_type_id != nullptr);
-    uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
+    dex::TypeIndex void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
     // Now we resolve void type so the dex cache contains it. We use java.lang.Object class
     // as referrer so the used dex cache is core's one.
-    ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get());
+    ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file,
+                                                      void_type_idx,
+                                                      java_lang_Object.Get());
     CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
     self->AssertNoPendingException();
   }
@@ -1941,13 +1949,36 @@
   void Visit(ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_) OVERRIDE {
     ClassTable* const class_table = class_loader->GetClassTable();
-    if (!done_ && class_table != nullptr && !class_table->Visit(*visitor_)) {
-      // If the visitor ClassTable returns false it means that we don't need to continue.
-      done_ = true;
+    if (!done_ && class_table != nullptr) {
+      DefiningClassLoaderFilterVisitor visitor(class_loader, visitor_);
+      if (!class_table->Visit(visitor)) {
+        // If the visitor ClassTable returns false it means that we don't need to continue.
+        done_ = true;
+      }
     }
   }
 
  private:
+  // Class visitor that limits the class visits from a ClassTable to the classes with
+  // the provided defining class loader. This filter is used to avoid multiple visits
+  // of the same class which can be recorded for multiple initiating class loaders.
+  class DefiningClassLoaderFilterVisitor : public ClassVisitor {
+   public:
+    DefiningClassLoaderFilterVisitor(ObjPtr<mirror::ClassLoader> defining_class_loader,
+                                     ClassVisitor* visitor)
+        : defining_class_loader_(defining_class_loader), visitor_(visitor) { }
+
+    bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+      if (klass->GetClassLoader() != defining_class_loader_) {
+        return true;
+      }
+      return (*visitor_)(klass);
+    }
+
+    ObjPtr<mirror::ClassLoader> const defining_class_loader_;
+    ClassVisitor* const visitor_;
+  };
+
   ClassVisitor* const visitor_;
   // If done is true then we don't need to do any more visiting.
   bool done_;
@@ -2532,56 +2563,109 @@
     }
   } else {
     ScopedObjectAccessUnchecked soa(self);
-    ObjPtr<mirror::Class> cp_klass;
-    if (FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &cp_klass)) {
-      // The chain was understood. So the value in cp_klass is either the class we were looking
-      // for, or not found.
-      if (cp_klass != nullptr) {
-        return cp_klass.Ptr();
-      }
-      // TODO: We handle the boot classpath loader in FindClassInBaseDexClassLoader. Try to unify
-      //       this and the branch above. TODO: throw the right exception here.
+    ObjPtr<mirror::Class> result_ptr;
+    bool descriptor_equals;
+    bool known_hierarchy =
+        FindClassInBaseDexClassLoader(soa, self, descriptor, hash, class_loader, &result_ptr);
+    if (result_ptr != nullptr) {
+      // The chain was understood and we found the class. We still need to add the class to
+      // the class table to protect from racy programs that can try and redefine the path list
+      // which would change the Class<?> returned for subsequent evaluation of const-class.
+      DCHECK(known_hierarchy);
+      DCHECK(result_ptr->DescriptorEquals(descriptor));
+      descriptor_equals = true;
+    } else {
+      // Either the chain wasn't understood or the class wasn't found.
+      //
+      // If the chain was understood and but we did not find the class, let the Java-side
+      // rediscover all this and throw the exception with the right stack trace. Note that
+      // the Java-side could still succeed for racy programs if another thread is actively
+      // modifying the class loader's path list.
 
-      // We'll let the Java-side rediscover all this and throw the exception with the right stack
-      // trace.
-    }
-
-    if (Runtime::Current()->IsAotCompiler()) {
-      // Oops, compile-time, can't run actual class-loader code.
-      ObjPtr<mirror::Throwable> pre_allocated = Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
-      self->SetException(pre_allocated);
-      return nullptr;
-    }
-
-    ScopedLocalRef<jobject> class_loader_object(soa.Env(),
-                                                soa.AddLocalReference<jobject>(class_loader.Get()));
-    std::string class_name_string(DescriptorToDot(descriptor));
-    ScopedLocalRef<jobject> result(soa.Env(), nullptr);
-    {
-      ScopedThreadStateChange tsc(self, kNative);
-      ScopedLocalRef<jobject> class_name_object(soa.Env(),
-                                                soa.Env()->NewStringUTF(class_name_string.c_str()));
-      if (class_name_object.get() == nullptr) {
-        DCHECK(self->IsExceptionPending());  // OOME.
+      if (Runtime::Current()->IsAotCompiler()) {
+        // Oops, compile-time, can't run actual class-loader code.
+        ObjPtr<mirror::Throwable> pre_allocated =
+            Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+        self->SetException(pre_allocated);
         return nullptr;
       }
-      CHECK(class_loader_object.get() != nullptr);
-      result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
-                                               WellKnownClasses::java_lang_ClassLoader_loadClass,
-                                               class_name_object.get()));
+
+      ScopedLocalRef<jobject> class_loader_object(
+          soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
+      std::string class_name_string(DescriptorToDot(descriptor));
+      ScopedLocalRef<jobject> result(soa.Env(), nullptr);
+      {
+        ScopedThreadStateChange tsc(self, kNative);
+        ScopedLocalRef<jobject> class_name_object(
+            soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str()));
+        if (class_name_object.get() == nullptr) {
+          DCHECK(self->IsExceptionPending());  // OOME.
+          return nullptr;
+        }
+        CHECK(class_loader_object.get() != nullptr);
+        result.reset(soa.Env()->CallObjectMethod(class_loader_object.get(),
+                                                 WellKnownClasses::java_lang_ClassLoader_loadClass,
+                                                 class_name_object.get()));
+      }
+      if (self->IsExceptionPending()) {
+        // If the ClassLoader threw, pass that exception up.
+        // However, to comply with the RI behavior, first check if another thread succeeded.
+        result_ptr = LookupClass(self, descriptor, hash, class_loader.Get());
+        if (result_ptr != nullptr && result_ptr->IsResolved()) {
+          self->ClearException();
+          return result_ptr.Ptr();
+        }
+        return nullptr;
+      } else if (result.get() == nullptr) {
+        // broken loader - throw NPE to be compatible with Dalvik
+        ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
+                                               class_name_string.c_str()).c_str());
+        return nullptr;
+      }
+      result_ptr = soa.Decode<mirror::Class>(result.get());
+      // Check the name of the returned class.
+      descriptor_equals = result_ptr->DescriptorEquals(descriptor);
     }
-    if (self->IsExceptionPending()) {
-      // If the ClassLoader threw, pass that exception up.
-      return nullptr;
-    } else if (result.get() == nullptr) {
-      // broken loader - throw NPE to be compatible with Dalvik
-      ThrowNullPointerException(StringPrintf("ClassLoader.loadClass returned null for %s",
-                                             class_name_string.c_str()).c_str());
-      return nullptr;
-    } else {
-      // success, return mirror::Class*
-      return soa.Decode<mirror::Class>(result.get()).Ptr();
+
+    // Try to insert the class to the class table, checking for mismatch.
+    ObjPtr<mirror::Class> old;
+    {
+      ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+      ClassTable* const class_table = InsertClassTableForClassLoader(class_loader.Get());
+      old = class_table->Lookup(descriptor, hash);
+      if (old == nullptr) {
+        old = result_ptr;  // For the comparison below, after releasing the lock.
+        if (descriptor_equals) {
+          class_table->InsertWithHash(result_ptr.Ptr(), hash);
+          Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(class_loader.Get());
+        }  // else throw below, after releasing the lock.
+      }
     }
+    if (UNLIKELY(old != result_ptr)) {
+      // Return `old` (even if `!descriptor_equals`) to mimic the RI behavior for parallel
+      // capable class loaders.  (All class loaders are considered parallel capable on Android.)
+      mirror::Class* loader_class = class_loader->GetClass();
+      const char* loader_class_name =
+          loader_class->GetDexFile().StringByTypeIdx(loader_class->GetDexTypeIndex());
+      LOG(WARNING) << "Initiating class loader of type " << DescriptorToDot(loader_class_name)
+          << " is not well-behaved; it a returned different Class for racing loadClass(\""
+          << DescriptorToDot(descriptor) << "\").";
+      return old.Ptr();
+    }
+    if (UNLIKELY(!descriptor_equals)) {
+      std::string result_storage;
+      const char* result_name = result_ptr->GetDescriptor(&result_storage);
+      std::string loader_storage;
+      const char* loader_class_name = class_loader->GetClass()->GetDescriptor(&loader_storage);
+      ThrowNoClassDefFoundError(
+          "Initiating class loader of type %s returned class %s instead of %s.",
+          DescriptorToDot(loader_class_name).c_str(),
+          DescriptorToDot(result_name).c_str(),
+          DescriptorToDot(descriptor).c_str());
+      return nullptr;
+    }
+    // success, return mirror::Class*
+    return result_ptr.Ptr();
   }
   UNREACHABLE();
 }
@@ -3662,12 +3746,6 @@
   Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass);
 }
 
-bool ClassLinker::RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader) {
-  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  ClassTable* const class_table = ClassTableForClassLoader(class_loader);
-  return class_table != nullptr && class_table->Remove(descriptor);
-}
-
 mirror::Class* ClassLinker::LookupClass(Thread* self,
                                         const char* descriptor,
                                         size_t hash,
@@ -4000,7 +4078,7 @@
 
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
   // In case we run without an image there won't be a backing oat file.
-  if (oat_dex_file == nullptr) {
+  if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
     return false;
   }
 
@@ -4090,7 +4168,7 @@
     for (; iterator.HasNext(); iterator.Next()) {
       // Ensure exception types are resolved so that they don't need resolution to be delivered,
       // unresolved exception types will be ignored by exception delivery
-      if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+      if (iterator.GetHandlerTypeIndex().IsValid()) {
         ObjPtr<mirror::Class> exception_type = ResolveType(iterator.GetHandlerTypeIndex(), method);
         if (exception_type == nullptr) {
           DCHECK(Thread::Current()->IsExceptionPending());
@@ -4756,7 +4834,7 @@
   const DexFile* dex_file = m->GetDexFile();
   const DexFile::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
   const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
-  uint16_t return_type_idx = proto_id.return_type_idx_;
+  dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
   std::string return_type = dex_file->PrettyType(return_type_idx);
   std::string class_loader = mirror::Object::PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
   ThrowWrappedLinkageError(klass.Get(),
@@ -4774,7 +4852,7 @@
                                                    ArtMethod* method,
                                                    ArtMethod* m,
                                                    uint32_t index,
-                                                   uint32_t arg_type_idx)
+                                                   dex::TypeIndex arg_type_idx)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(Thread::Current()->IsExceptionPending());
   DCHECK(!m->IsProxyMethod());
@@ -4864,7 +4942,7 @@
   }
   for (uint32_t i = 0; i < num_types; ++i) {
     StackHandleScope<1> hs(self);
-    uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
+    dex::TypeIndex param_type_idx = types1->GetTypeItem(i).type_idx_;
     Handle<mirror::Class> param_type(hs.NewHandle(
         method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
     if (UNLIKELY(param_type.Get() == nullptr)) {
@@ -4872,7 +4950,7 @@
                                              method1, i, param_type_idx);
       return false;
     }
-    uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
+    dex::TypeIndex other_param_type_idx = types2->GetTypeItem(i).type_idx_;
     ObjPtr<mirror::Class> other_param_type =
         method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
     if (UNLIKELY(other_param_type == nullptr)) {
@@ -5356,8 +5434,8 @@
 bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
   CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
-  uint16_t super_class_idx = class_def.superclass_idx_;
-  if (super_class_idx != DexFile::kDexNoIndex16) {
+  dex::TypeIndex super_class_idx = class_def.superclass_idx_;
+  if (super_class_idx.IsValid()) {
     // Check that a class does not inherit from itself directly.
     //
     // TODO: This is a cheap check to detect the straightforward case
@@ -5394,7 +5472,7 @@
   const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
   if (interfaces != nullptr) {
     for (size_t i = 0; i < interfaces->Size(); i++) {
-      uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
+      dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
       ObjPtr<mirror::Class> interface = ResolveType(dex_file, idx, klass.Get());
       if (interface == nullptr) {
         DCHECK(Thread::Current()->IsExceptionPending());
@@ -7510,7 +7588,7 @@
 }
 
 ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
-                                                      uint16_t type_idx,
+                                                      dex::TypeIndex type_idx,
                                                       ObjPtr<mirror::DexCache> dex_cache,
                                                       ObjPtr<mirror::ClassLoader> class_loader) {
   ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
@@ -7536,7 +7614,7 @@
 }
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
-                                        uint16_t type_idx,
+                                        dex::TypeIndex type_idx,
                                         ObjPtr<mirror::Class> referrer) {
   StackHandleScope<2> hs(Thread::Current());
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
@@ -7545,7 +7623,7 @@
 }
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
-                                        uint16_t type_idx,
+                                        dex::TypeIndex type_idx,
                                         Handle<mirror::DexCache> dex_cache,
                                         Handle<mirror::ClassLoader> class_loader) {
   DCHECK(dex_cache.Get() != nullptr);
@@ -7939,7 +8017,7 @@
   int32_t i = 0;
   MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
   for (; it.HasNext(); it.Next()) {
-    const uint16_t type_idx = it.GetTypeIdx();
+    const dex::TypeIndex type_idx = it.GetTypeIdx();
     param_class.Assign(ResolveType(dex_file, type_idx, dex_cache, class_loader));
     if (param_class.Get() == nullptr) {
       DCHECK(self->IsExceptionPending());
@@ -8350,10 +8428,10 @@
                                              dex_file->GetBaseLocation(),
                                              dex_file->GetLocationChecksum());
     size_t num_resolved = 0;
-    std::unordered_set<uint16_t> class_set;
+    std::unordered_set<dex::TypeIndex> class_set;
     CHECK_EQ(num_types, dex_cache->NumResolvedTypes());
     for (size_t i = 0; i < num_types; ++i) {
-      ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(i);
+      ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
       // Filter out null class loader since that is the boot class loader.
       if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) {
         continue;
@@ -8418,7 +8496,7 @@
       VLOG(profiler) << "Found opened dex file for " << dex_file->GetLocation() << " with "
                      << info.GetClasses().size() << " classes";
       DCHECK_EQ(dex_file->GetLocationChecksum(), info.GetLocationChecksum());
-      for (uint16_t type_idx : info.GetClasses()) {
+      for (dex::TypeIndex type_idx : info.GetClasses()) {
         const DexFile::TypeId& type_id = dex_file->GetTypeId(type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         ret.insert(descriptor);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 1d29e31..88028ea 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -32,6 +32,7 @@
 #include "class_table.h"
 #include "dex_cache_resolved_classes.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "gc_root.h"
 #include "jni.h"
 #include "mirror/class.h"
@@ -217,12 +218,6 @@
 
   mirror::Class* FindPrimitiveClass(char type) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // General class unloading is not supported, this is used to prune
-  // unwanted classes during image writing.
-  bool RemoveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> class_loader)
-      REQUIRES(!Locks::classlinker_classes_lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   void DumpAllClasses(int flags)
       REQUIRES(!Locks::classlinker_classes_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -255,7 +250,7 @@
   // result in the DexCache. The referrer is used to identify the
   // target DexCache and ClassLoader to use for resolution.
   mirror::Class* ResolveType(const DexFile& dex_file,
-                             uint16_t type_idx,
+                             dex::TypeIndex type_idx,
                              ObjPtr<mirror::Class> referrer)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!dex_lock_, !Roles::uninterruptible_);
@@ -263,18 +258,18 @@
   // Resolve a Type with the given index from the DexFile, storing the
   // result in the DexCache. The referrer is used to identify the
   // target DexCache and ClassLoader to use for resolution.
-  mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer)
+  mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
-  mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer)
+  mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!dex_lock_, !Roles::uninterruptible_);
 
   // Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
   // for the type, since it may be referenced from but not contained within the given DexFile.
   ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file,
-                                           uint16_t type_idx,
+                                           dex::TypeIndex type_idx,
                                            ObjPtr<mirror::DexCache> dex_cache,
                                            ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -284,7 +279,7 @@
   // type, since it may be referenced from but not contained within
   // the given DexFile.
   mirror::Class* ResolveType(const DexFile& dex_file,
-                             uint16_t type_idx,
+                             dex::TypeIndex type_idx,
                              Handle<mirror::DexCache> dex_cache,
                              Handle<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 44590ba..9e17be2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -25,6 +25,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "experimental_flags.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "gc/heap.h"
@@ -429,7 +430,7 @@
     }
     // Verify all the types referenced by this file
     for (size_t i = 0; i < dex.NumTypeIds(); i++) {
-      const DexFile::TypeId& type_id = dex.GetTypeId(i);
+      const DexFile::TypeId& type_id = dex.GetTypeId(dex::TypeIndex(i));
       const char* descriptor = dex.GetTypeDescriptor(type_id);
       AssertDexFileClass(class_loader, descriptor);
     }
@@ -891,7 +892,7 @@
       hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
   AssertNonExistentClass("LMyClass;");
   ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
-  uint32_t type_idx = klass->GetClassDef()->class_idx_;
+  dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
   ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
   const DexFile& dex_file = klass->GetDexFile();
   EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
@@ -1154,7 +1155,7 @@
   ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
   const DexFile::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
   ASSERT_TRUE(type_id != nullptr);
-  uint32_t type_idx = dex_file->GetIndexForTypeId(*type_id);
+  dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
   mirror::Class* uninit = ResolveVerifyAndClinit(type_idx, clinit, soa.Self(), true, false);
   EXPECT_TRUE(uninit != nullptr);
   EXPECT_FALSE(uninit->IsInitialized());
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index b44104e..bd477ea 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -142,7 +142,6 @@
 
 bool ClassTable::ClassDescriptorHashEquals::operator()(const GcRoot<mirror::Class>& a,
                                                        const GcRoot<mirror::Class>& b) const {
-  DCHECK_EQ(a.Read()->GetClassLoader(), b.Read()->GetClassLoader());
   std::string temp;
   return a.Read()->DescriptorEquals(b.Read()->GetDescriptor(&temp));
 }
@@ -170,7 +169,7 @@
     const DexFile* dex_file = ObjPtr<mirror::DexCache>::DownCast(obj)->GetDexFile();
     if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) {
       const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile();
-      if (!oat_file->GetBssGcRoots().empty()) {
+      if (oat_file != nullptr && !oat_file->GetBssGcRoots().empty()) {
         InsertOatFileLocked(oat_file);  // Ignore return value.
       }
     }
diff --git a/runtime/dex_cache_resolved_classes.h b/runtime/dex_cache_resolved_classes.h
index 0febbed..f53ca4a 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/runtime/dex_cache_resolved_classes.h
@@ -21,6 +21,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include "dex_file_types.h"
+
 namespace art {
 
 // Data structure for passing around which classes belonging to a dex cache / dex file are resolved.
@@ -59,7 +61,7 @@
     return location_checksum_;
   }
 
-  const std::unordered_set<uint16_t>& GetClasses() const {
+  const std::unordered_set<dex::TypeIndex>& GetClasses() const {
     return classes_;
   }
 
@@ -68,7 +70,7 @@
   const std::string base_location_;
   const uint32_t location_checksum_;
   // Array of resolved class def indexes.
-  mutable std::unordered_set<uint16_t> classes_;
+  mutable std::unordered_set<dex::TypeIndex> classes_;
 };
 
 inline bool operator<(const DexCacheResolvedClasses& a, const DexCacheResolvedClasses& b) {
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 621b2c5..77a63c1 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -58,12 +58,12 @@
   return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
 }
 
-inline const char* DexFile::StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
   const TypeId& type_id = GetTypeId(idx);
   return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
 }
 
-inline const char* DexFile::StringByTypeIdx(uint32_t idx) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
   const TypeId& type_id = GetTypeId(idx);
   return StringDataByIdx(type_id.descriptor_idx_);
 }
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 2ef7509..cc544fd 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -26,6 +26,7 @@
 
 #include <memory>
 #include <sstream>
+#include <type_traits>
 
 #include "base/enums.h"
 #include "base/file_magic.h"
@@ -44,6 +45,9 @@
 
 namespace art {
 
+static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
+static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
+
 static constexpr OatDexFile* kNoOatDexFile = nullptr;
 
 const char* DexFile::kClassesDex = "classes.dex";
@@ -550,7 +554,7 @@
   return atoi(version);
 }
 
-const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const {
+const DexFile::ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
   size_t num_class_defs = NumClassDefs();
   // Fast path for rare no class defs case.
   if (num_class_defs == 0) {
@@ -597,9 +601,9 @@
                                              const DexFile::StringId& name,
                                              const DexFile::TypeId& type) const {
   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
-  const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+  const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
-  const uint16_t type_idx = GetIndexForTypeId(type);
+  const dex::TypeIndex type_idx = GetIndexForTypeId(type);
   int32_t lo = 0;
   int32_t hi = NumFieldIds() - 1;
   while (hi >= lo) {
@@ -632,7 +636,7 @@
                                                const DexFile::StringId& name,
                                                const DexFile::ProtoId& signature) const {
   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
-  const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+  const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
   const uint32_t name_idx = GetIndexForStringId(name);
   const uint16_t proto_idx = GetIndexForProtoId(signature);
   int32_t lo = 0;
@@ -687,7 +691,7 @@
   int32_t hi = NumTypeIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
-    const TypeId& type_id = GetTypeId(mid);
+    const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
     const DexFile::StringId& str_id = GetStringId(type_id.descriptor_idx_);
     const char* str = GetStringData(str_id);
     int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
@@ -726,7 +730,7 @@
   int32_t hi = NumTypeIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
-    const TypeId& type_id = GetTypeId(mid);
+    const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
     if (string_idx > type_id.descriptor_idx_) {
       lo = mid + 1;
     } else if (string_idx < type_id.descriptor_idx_) {
@@ -738,20 +742,20 @@
   return nullptr;
 }
 
-const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
-                                             const uint16_t* signature_type_idxs,
+const DexFile::ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
+                                             const dex::TypeIndex* signature_type_idxs,
                                              uint32_t signature_length) const {
   int32_t lo = 0;
   int32_t hi = NumProtoIds() - 1;
   while (hi >= lo) {
     int32_t mid = (hi + lo) / 2;
     const DexFile::ProtoId& proto = GetProtoId(mid);
-    int compare = return_type_idx - proto.return_type_idx_;
+    int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
     if (compare == 0) {
       DexFileParameterIterator it(*this, proto);
       size_t i = 0;
       while (it.HasNext() && i < signature_length && compare == 0) {
-        compare = signature_type_idxs[i] - it.GetTypeIdx();
+        compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
         it.Next();
         i++;
       }
@@ -775,8 +779,9 @@
 }
 
 // Given a signature place the type ids into the given vector
-bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
-                             std::vector<uint16_t>* param_type_idxs) const {
+bool DexFile::CreateTypeList(const StringPiece& signature,
+                             dex::TypeIndex* return_type_idx,
+                             std::vector<dex::TypeIndex>* param_type_idxs) const {
   if (signature[0] != '(') {
     return false;
   }
@@ -813,7 +818,7 @@
     if (type_id == nullptr) {
       return false;
     }
-    uint16_t type_idx = GetIndexForTypeId(*type_id);
+    dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
     if (!process_return) {
       param_type_idxs->push_back(type_idx);
     } else {
@@ -825,8 +830,8 @@
 }
 
 const Signature DexFile::CreateSignature(const StringPiece& signature) const {
-  uint16_t return_type_idx;
-  std::vector<uint16_t> param_type_indices;
+  dex::TypeIndex return_type_idx;
+  std::vector<dex::TypeIndex> param_type_indices;
   bool success = CreateTypeList(signature, &return_type_idx, &param_type_indices);
   if (!success) {
     return Signature::NoSignature();
@@ -971,7 +976,8 @@
         }
 
         local_in_reg[reg].name_ = StringDataByIdx(name_idx);
-        local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx);
+        local_in_reg[reg].descriptor_ =
+            StringByTypeIdx(dex::TypeIndex(dchecked_integral_cast<uint16_t>(descriptor_idx)));;
         local_in_reg[reg].signature_ = StringDataByIdx(signature_idx);
         local_in_reg[reg].start_address_ = address;
         local_in_reg[reg].reg_ = reg;
@@ -1225,9 +1231,9 @@
   return result;
 }
 
-std::string DexFile::PrettyType(uint32_t type_idx) const {
-  if (type_idx >= NumTypeIds()) {
-    return StringPrintf("<<invalid-type-idx-%d>>", type_idx);
+std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
+  if (type_idx.index_ >= NumTypeIds()) {
+    return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
   }
   const DexFile::TypeId& type_id = GetTypeId(type_idx);
   return PrettyDescriptor(GetTypeDescriptor(type_id));
@@ -1457,14 +1463,14 @@
 
 void CatchHandlerIterator::Next() {
   if (remaining_count_ > 0) {
-    handler_.type_idx_ = DecodeUnsignedLeb128(&current_data_);
+    handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(&current_data_));
     handler_.address_  = DecodeUnsignedLeb128(&current_data_);
     remaining_count_--;
     return;
   }
 
   if (catch_all_) {
-    handler_.type_idx_ = DexFile::kDexNoIndex16;
+    handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
     handler_.address_  = DecodeUnsignedLeb128(&current_data_);
     catch_all_ = false;
     return;
@@ -1474,4 +1480,13 @@
   remaining_count_ = -1;
 }
 
+namespace dex {
+
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
+  os << "TypeIndex[" << index.index_ << "]";
+  return os;
+}
+
+}  // namespace dex
+
 }  // namespace art
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index da9fa50..2384eb6 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -23,6 +23,7 @@
 
 #include "base/logging.h"
 #include "base/value_object.h"
+#include "dex_file_types.h"
 #include "globals.h"
 #include "invoke_type.h"
 #include "jni.h"
@@ -159,17 +160,28 @@
 
   // Raw field_id_item.
   struct FieldId {
-    uint16_t class_idx_;  // index into type_ids_ array for defining class
-    uint16_t type_idx_;  // index into type_ids_ array for field type
+    dex::TypeIndex class_idx_;  // index into type_ids_ array for defining class
+    dex::TypeIndex type_idx_;  // index into type_ids_ array for field type
     uint32_t name_idx_;  // index into string_ids_ array for field name
 
    private:
     DISALLOW_COPY_AND_ASSIGN(FieldId);
   };
 
+  // Raw proto_id_item.
+  struct ProtoId {
+    uint32_t shorty_idx_;        // index into string_ids array for shorty descriptor
+    dex::TypeIndex return_type_idx_;  // index into type_ids array for return type
+    uint16_t pad_;               // padding = 0
+    uint32_t parameters_off_;    // file offset to type_list for parameter types
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ProtoId);
+  };
+
   // Raw method_id_item.
   struct MethodId {
-    uint16_t class_idx_;  // index into type_ids_ array for defining class
+    dex::TypeIndex class_idx_;   // index into type_ids_ array for defining class
     uint16_t proto_idx_;  // index into proto_ids_ array for method prototype
     uint32_t name_idx_;  // index into string_ids_ array for method name
 
@@ -177,23 +189,12 @@
     DISALLOW_COPY_AND_ASSIGN(MethodId);
   };
 
-  // Raw proto_id_item.
-  struct ProtoId {
-    uint32_t shorty_idx_;  // index into string_ids array for shorty descriptor
-    uint16_t return_type_idx_;  // index into type_ids array for return type
-    uint16_t pad_;             // padding = 0
-    uint32_t parameters_off_;  // file offset to type_list for parameter types
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(ProtoId);
-  };
-
   // Raw class_def_item.
   struct ClassDef {
-    uint16_t class_idx_;  // index into type_ids_ array for this class
+    dex::TypeIndex class_idx_;  // index into type_ids_ array for this class
     uint16_t pad1_;  // padding = 0
     uint32_t access_flags_;
-    uint16_t superclass_idx_;  // index into type_ids_ array for superclass
+    dex::TypeIndex superclass_idx_;  // index into type_ids_ array for superclass
     uint16_t pad2_;  // padding = 0
     uint32_t interfaces_off_;  // file offset to TypeList
     uint32_t source_file_idx_;  // index into string_ids_ for source file name
@@ -225,7 +226,7 @@
 
   // Raw type_item.
   struct TypeItem {
-    uint16_t type_idx_;  // index into type_ids section
+    dex::TypeIndex type_idx_;  // index into type_ids section
 
    private:
     DISALLOW_COPY_AND_ASSIGN(TypeItem);
@@ -540,23 +541,23 @@
   }
 
   // Returns the TypeId at the specified index.
-  const TypeId& GetTypeId(uint32_t idx) const {
-    DCHECK_LT(idx, NumTypeIds()) << GetLocation();
-    return type_ids_[idx];
+  const TypeId& GetTypeId(dex::TypeIndex idx) const {
+    DCHECK_LT(idx.index_, NumTypeIds()) << GetLocation();
+    return type_ids_[idx.index_];
   }
 
-  uint16_t GetIndexForTypeId(const TypeId& type_id) const {
+  dex::TypeIndex GetIndexForTypeId(const TypeId& type_id) const {
     CHECK_GE(&type_id, type_ids_) << GetLocation();
     CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_) << GetLocation();
     size_t result = &type_id - type_ids_;
     DCHECK_LT(result, 65536U) << GetLocation();
-    return static_cast<uint16_t>(result);
+    return dex::TypeIndex(static_cast<uint16_t>(result));
   }
 
   // Get the descriptor string associated with a given type index.
-  const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const;
+  const char* StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const;
 
-  const char* StringByTypeIdx(uint32_t idx) const;
+  const char* StringByTypeIdx(dex::TypeIndex idx) const;
 
   // Returns the type descriptor string of a type id.
   const char* GetTypeDescriptor(const TypeId& type_id) const;
@@ -671,7 +672,7 @@
   const char* GetClassDescriptor(const ClassDef& class_def) const;
 
   // Looks up a class definition by its type index.
-  const ClassDef* FindClassDef(uint16_t type_idx) const;
+  const ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
 
   const TypeList* GetInterfacesList(const ClassDef& class_def) const {
     if (class_def.interfaces_off_ == 0) {
@@ -711,7 +712,7 @@
   }
 
   // Returns the ProtoId at the specified index.
-  const ProtoId& GetProtoId(uint32_t idx) const {
+  const ProtoId& GetProtoId(uint16_t idx) const {
     DCHECK_LT(idx, NumProtoIds()) << GetLocation();
     return proto_ids_[idx];
   }
@@ -723,16 +724,18 @@
   }
 
   // Looks up a proto id for a given return type and signature type list
-  const ProtoId* FindProtoId(uint16_t return_type_idx,
-                             const uint16_t* signature_type_idxs, uint32_t signature_length) const;
-  const ProtoId* FindProtoId(uint16_t return_type_idx,
-                             const std::vector<uint16_t>& signature_type_idxs) const {
+  const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+                             const dex::TypeIndex* signature_type_idxs,
+                             uint32_t signature_length) const;
+  const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+                             const std::vector<dex::TypeIndex>& signature_type_idxs) const {
     return FindProtoId(return_type_idx, &signature_type_idxs[0], signature_type_idxs.size());
   }
 
   // Given a signature place the type ids into the given vector, returns true on success
-  bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
-                      std::vector<uint16_t>* param_type_idxs) const;
+  bool CreateTypeList(const StringPiece& signature,
+                      dex::TypeIndex* return_type_idx,
+                      std::vector<dex::TypeIndex>* param_type_idxs) const;
 
   // Create a Signature from the given string signature or return Signature::NoSignature if not
   // possible.
@@ -1010,6 +1013,11 @@
     return oat_dex_file_;
   }
 
+  // Used by oat writer.
+  void SetOatDexFile(OatDexFile* oat_dex_file) const {
+    oat_dex_file_ = oat_dex_file;
+  }
+
   // Utility methods for reading integral values from a buffer.
   static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
   static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
@@ -1021,7 +1029,7 @@
   // Returns a human-readable form of the field at an index.
   std::string PrettyField(uint32_t field_idx, bool with_type = true) const;
   // Returns a human-readable form of the type at an index.
-  std::string PrettyType(uint32_t type_idx) const;
+  std::string PrettyType(dex::TypeIndex type_idx) const;
 
  private:
   static std::unique_ptr<const DexFile> OpenFile(int fd,
@@ -1138,9 +1146,10 @@
   // If this dex file was loaded from an oat file, oat_dex_file_ contains a
   // pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
   // null.
-  const OatDexFile* oat_dex_file_;
+  mutable const OatDexFile* oat_dex_file_;
 
   friend class DexFileVerifierTest;
+  friend class OatWriter;
   ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for constructor
 };
 
@@ -1165,11 +1174,11 @@
   bool HasNext() const { return pos_ < size_; }
   size_t Size() const { return size_; }
   void Next() { ++pos_; }
-  uint16_t GetTypeIdx() {
+  dex::TypeIndex GetTypeIdx() {
     return type_list_->GetTypeItem(pos_).type_idx_;
   }
   const char* GetDescriptor() {
-    return dex_file_.StringByTypeIdx(GetTypeIdx());
+    return dex_file_.StringByTypeIdx(dex::TypeIndex(GetTypeIdx()));
   }
  private:
   const DexFile& dex_file_;
@@ -1455,7 +1464,7 @@
       Init(handler_data);
     }
 
-    uint16_t GetHandlerTypeIndex() const {
+    dex::TypeIndex GetHandlerTypeIndex() const {
       return handler_.type_idx_;
     }
     uint32_t GetHandlerAddress() const {
@@ -1476,7 +1485,7 @@
     void Init(const uint8_t* handler_data);
 
     struct CatchHandlerItem {
-      uint16_t type_idx_;  // type index of the caught exception type
+      dex::TypeIndex type_idx_;  // type index of the caught exception type
       uint32_t address_;  // handler address
     } handler_;
     const uint8_t* current_data_;  // the current handler in dex file.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 835f456..3fe2c40 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -90,7 +90,7 @@
     const uint8_t* annotation = annotation_item->annotation_;
     uint32_t type_index = DecodeUnsignedLeb128(&annotation);
 
-    if (strcmp(descriptor, dex_file.StringByTypeIdx(type_index)) == 0) {
+    if (strcmp(descriptor, dex_file.StringByTypeIdx(dex::TypeIndex(type_index))) == 0) {
       result = annotation_item;
       break;
     }
@@ -246,7 +246,7 @@
   StackHandleScope<2> hs(self);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Handle<mirror::Class> annotation_class(hs.NewHandle(
-      class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
+      class_linker->ResolveType(klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get())));
   if (annotation_class.Get() == nullptr) {
     LOG(INFO) << "Unable to resolve " << klass->PrettyClass() << " annotation class " << type_index;
     DCHECK(Thread::Current()->IsExceptionPending());
@@ -370,13 +370,14 @@
       if (result_style == DexFile::kAllRaw) {
         annotation_value->value_.SetI(index);
       } else {
+        dex::TypeIndex type_index(index);
         element_object = Runtime::Current()->GetClassLinker()->ResolveType(
-            klass->GetDexFile(), index, klass.Get());
+            klass->GetDexFile(), type_index, klass.Get());
         set_object = true;
         if (element_object == nullptr) {
           CHECK(self->IsExceptionPending());
           if (result_style == DexFile::kAllObjects) {
-            const char* msg = dex_file.StringByTypeIdx(index);
+            const char* msg = dex_file.StringByTypeIdx(type_index);
             self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg);
             element_object = self->GetException();
             self->ClearException();
@@ -665,7 +666,7 @@
     const uint8_t* annotation = annotation_item->annotation_;
     uint32_t type_index = DecodeUnsignedLeb128(&annotation);
     mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
-        klass->GetDexFile(), type_index, klass.Get());
+        klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get());
     if (resolved_class == nullptr) {
       std::string temp;
       LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
@@ -1345,7 +1346,9 @@
       break;
     }
     case kType: {
-      mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
+      mirror::Class* resolved = linker_->ResolveType(dex_file_,
+                                                     dex::TypeIndex(jval_.i),
+                                                     *dex_cache_,
                                                      *class_loader_);
       field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
       break;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8e1501f..f94d07b 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -415,14 +415,14 @@
 
 TEST_F(DexFileTest, FindTypeId) {
   for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
-    const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
+    const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i));
     const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
     ASSERT_TRUE(type_str_id != nullptr);
     uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
     const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
     ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
     ASSERT_TRUE(type_id != nullptr);
-    EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
+    EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i);
   }
 }
 
@@ -430,7 +430,7 @@
   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
     const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
     const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
-    std::vector<uint16_t> to_find_types;
+    std::vector<dex::TypeIndex> to_find_types;
     if (to_find_tl != nullptr) {
       for (size_t j = 0; j < to_find_tl->Size(); j++) {
         to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
diff --git a/runtime/dex_file_types.h b/runtime/dex_file_types.h
new file mode 100644
index 0000000..c6d95a1
--- /dev/null
+++ b/runtime/dex_file_types.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_TYPES_H_
+#define ART_RUNTIME_DEX_FILE_TYPES_H_
+
+#include <limits>
+#include <ostream>
+
+namespace art {
+namespace dex {
+
+class TypeIndex {
+ public:
+  uint16_t index_;
+
+  TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
+  explicit TypeIndex(uint16_t idx) : index_(idx) {}
+
+  bool IsValid() const {
+    return index_ != std::numeric_limits<decltype(index_)>::max();
+  }
+  static TypeIndex Invalid() {
+    return TypeIndex(std::numeric_limits<decltype(index_)>::max());
+  }
+
+  bool operator==(const TypeIndex& other) const {
+    return index_ == other.index_;
+  }
+  bool operator!=(const TypeIndex& other) const {
+    return index_ != other.index_;
+  }
+  bool operator<(const TypeIndex& other) const {
+    return index_ < other.index_;
+  }
+  bool operator<=(const TypeIndex& other) const {
+    return index_ <= other.index_;
+  }
+  bool operator>(const TypeIndex& other) const {
+    return index_ > other.index_;
+  }
+  bool operator>=(const TypeIndex& other) const {
+    return index_ >= other.index_;
+  }
+};
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index);
+
+}  // namespace dex
+}  // namespace art
+
+namespace std {
+
+template<> struct hash<art::dex::TypeIndex> {
+  size_t operator()(const art::dex::TypeIndex& index) const {
+    return hash<uint16_t>()(index.index_);
+  }
+};
+
+}  // namespace std
+
+#endif  // ART_RUNTIME_DEX_FILE_TYPES_H_
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index be25803..68e9f73 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -76,8 +76,9 @@
   return dex_file_->StringDataByIdx(idx);
 }
 
-const char* DexFileVerifier::CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_string) {
-  if (UNLIKELY(!CheckIndex(type_idx, dex_file_->NumTypeIds(), error_string))) {
+const char* DexFileVerifier::CheckLoadStringByTypeIdx(dex::TypeIndex type_idx,
+                                                      const char* error_string) {
+  if (UNLIKELY(!CheckIndex(type_idx.index_, dex_file_->NumTypeIds(), error_string))) {
     return nullptr;
   }
   const DexFile::TypeId& type_id = dex_file_->GetTypeId(type_idx);
@@ -525,7 +526,7 @@
 bool DexFileVerifier::CheckClassDataItemField(uint32_t idx,
                                               uint32_t access_flags,
                                               uint32_t class_access_flags,
-                                              uint16_t class_type_index,
+                                              dex::TypeIndex class_type_index,
                                               bool expect_static) {
   // Check for overflow.
   if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) {
@@ -533,13 +534,13 @@
   }
 
   // Check that it's the right class.
-  uint16_t my_class_index =
+  dex::TypeIndex my_class_index =
       (reinterpret_cast<const DexFile::FieldId*>(begin_ + header_->field_ids_off_) + idx)->
           class_idx_;
   if (class_type_index != my_class_index) {
     ErrorStringPrintf("Field's class index unexpected, %" PRIu16 "vs %" PRIu16,
-                      my_class_index,
-                      class_type_index);
+                      my_class_index.index_,
+                      class_type_index.index_);
     return false;
   }
 
@@ -563,7 +564,7 @@
 bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx,
                                                uint32_t access_flags,
                                                uint32_t class_access_flags,
-                                               uint16_t class_type_index,
+                                               dex::TypeIndex class_type_index,
                                                uint32_t code_offset,
                                                std::unordered_set<uint32_t>* direct_method_indexes,
                                                bool expect_direct) {
@@ -574,13 +575,13 @@
   }
 
   // Check that it's the right class.
-  uint16_t my_class_index =
+  dex::TypeIndex my_class_index =
       (reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)->
           class_idx_;
   if (class_type_index != my_class_index) {
     ErrorStringPrintf("Method's class index unexpected, %" PRIu16 "vs %" PRIu16,
-                      my_class_index,
-                      class_type_index);
+                      my_class_index.index_,
+                      class_type_index.index_);
     return false;
   }
 
@@ -789,7 +790,7 @@
 
 bool DexFileVerifier::FindClassFlags(uint32_t index,
                                      bool is_field,
-                                     uint16_t* class_type_index,
+                                     dex::TypeIndex* class_type_index,
                                      uint32_t* class_access_flags) {
   DCHECK(class_type_index != nullptr);
   DCHECK(class_access_flags != nullptr);
@@ -811,7 +812,7 @@
   }
 
   // Check if that is valid.
-  if (*class_type_index >= header_->type_ids_size_) {
+  if (class_type_index->index_ >= header_->type_ids_size_) {
     return false;
   }
 
@@ -836,7 +837,7 @@
                                                  uint32_t curr_index,
                                                  uint32_t prev_index,
                                                  bool* have_class,
-                                                 uint16_t* class_type_index,
+                                                 dex::TypeIndex* class_type_index,
                                                  uint32_t* class_access_flags) {
   if (curr_index < prev_index) {
     ErrorStringPrintf("out-of-order %s indexes %" PRIu32 " and %" PRIu32,
@@ -862,7 +863,7 @@
 template <bool kStatic>
 bool DexFileVerifier::CheckIntraClassDataItemFields(ClassDataItemIterator* it,
                                                     bool* have_class,
-                                                    uint16_t* class_type_index,
+                                                    dex::TypeIndex* class_type_index,
                                                     uint32_t* class_access_flags) {
   DCHECK(it != nullptr);
   // These calls use the raw access flags to check whether the whole dex field is valid.
@@ -897,7 +898,7 @@
     ClassDataItemIterator* it,
     std::unordered_set<uint32_t>* direct_method_indexes,
     bool* have_class,
-    uint16_t* class_type_index,
+    dex::TypeIndex* class_type_index,
     uint32_t* class_access_flags) {
   uint32_t prev_index = 0;
   for (; kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); it->Next()) {
@@ -935,7 +936,7 @@
   // So we need to explicitly search with the first item we find (either field or method), and then,
   // as the lookup is expensive, cache the result.
   bool have_class = false;
-  uint16_t class_type_index;
+  dex::TypeIndex class_type_index;
   uint32_t class_access_flags;
 
   // Check fields.
@@ -1682,26 +1683,27 @@
   return true;
 }
 
-uint16_t DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
   ClassDataItemIterator it(*dex_file_, ptr);
   *success = true;
 
   if (it.HasNextStaticField() || it.HasNextInstanceField()) {
     LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id",
-               *success = false; return DexFile::kDexNoIndex16)
+               *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return field->class_idx_;
   }
 
   if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
     LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
-                *success = false; return DexFile::kDexNoIndex16)
+                *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return method->class_idx_;
   }
 
-  return DexFile::kDexNoIndex16;
+  return dex::TypeIndex(DexFile::kDexNoIndex16);
 }
 
-uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr,
+                                                                     bool* success) {
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
   *success = true;
@@ -1709,25 +1711,25 @@
   if (item->fields_size_ != 0) {
     DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
     LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id",
-               *success = false; return DexFile::kDexNoIndex16)
+               *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return field->class_idx_;
   }
 
   if (item->methods_size_ != 0) {
     DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
     LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
-                *success = false; return DexFile::kDexNoIndex16)
+                *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return method->class_idx_;
   }
 
   if (item->parameters_size_ != 0) {
     DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
     LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
-                *success = false; return DexFile::kDexNoIndex16)
+                *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
     return method->class_idx_;
   }
 
-  return DexFile::kDexNoIndex16;
+  return dex::TypeIndex(DexFile::kDexNoIndex16);
 }
 
 bool DexFileVerifier::CheckInterStringIdItem() {
@@ -1797,7 +1799,8 @@
 
   DexFileParameterIterator it(*dex_file_, *item);
   while (it.HasNext() && *shorty != '\0') {
-    if (!CheckIndex(it.GetTypeIdx(), dex_file_->NumTypeIds(),
+    if (!CheckIndex(it.GetTypeIdx().index_,
+                    dex_file_->NumTypeIds(),
                     "inter_proto_id_item shorty type_idx")) {
       return false;
     }
@@ -1824,10 +1827,10 @@
       DexFileParameterIterator prev_it(*dex_file_, *prev);
 
       while (curr_it.HasNext() && prev_it.HasNext()) {
-        uint16_t prev_idx = prev_it.GetTypeIdx();
-        uint16_t curr_idx = curr_it.GetTypeIdx();
-        DCHECK_NE(prev_idx, DexFile::kDexNoIndex16);
-        DCHECK_NE(curr_idx, DexFile::kDexNoIndex16);
+        dex::TypeIndex prev_idx = prev_it.GetTypeIdx();
+        dex::TypeIndex curr_idx = curr_it.GetTypeIdx();
+        DCHECK_NE(prev_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
+        DCHECK_NE(curr_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
 
         if (prev_idx < curr_idx) {
           break;
@@ -1951,7 +1954,7 @@
 
   // Check for duplicate class def.
   if (defined_classes_.find(item->class_idx_) != defined_classes_.end()) {
-    ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_);
+    ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
     return false;
   }
   defined_classes_.insert(item->class_idx_);
@@ -1985,12 +1988,13 @@
     return false;
   }
 
-  if (item->superclass_idx_ != DexFile::kDexNoIndex16) {
+  if (item->superclass_idx_.IsValid()) {
     if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) {
       // Check that a class does not inherit from itself directly (by having
       // the same type idx as its super class).
       if (UNLIKELY(item->superclass_idx_ == item->class_idx_)) {
-        ErrorStringPrintf("Class with same type idx as its superclass: '%d'", item->class_idx_);
+        ErrorStringPrintf("Class with same type idx as its superclass: '%d'",
+                          item->class_idx_.index_);
         return false;
       }
 
@@ -2004,8 +2008,8 @@
           ErrorStringPrintf("Invalid class definition ordering:"
                             " class with type idx: '%d' defined before"
                             " superclass with type idx: '%d'",
-                            item->class_idx_,
-                            item->superclass_idx_);
+                            item->class_idx_.index_,
+                            item->superclass_idx_.index_);
           return false;
         }
       }
@@ -2029,7 +2033,7 @@
         // same type idx as one of its immediate implemented interfaces).
         if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) {
           ErrorStringPrintf("Class with same type idx as implemented interface: '%d'",
-                            item->class_idx_);
+                            item->class_idx_.index_);
           return false;
         }
 
@@ -2044,8 +2048,8 @@
             ErrorStringPrintf("Invalid class definition ordering:"
                               " class with type idx: '%d' defined before"
                               " implemented interface with type idx: '%d'",
-                              item->class_idx_,
-                              interfaces->GetTypeItem(i).type_idx_);
+                              item->class_idx_.index_,
+                              interfaces->GetTypeItem(i).type_idx_.index_);
             return false;
           }
         }
@@ -2065,9 +2069,9 @@
      * practice the number of interfaces implemented by any given class is low.
      */
     for (uint32_t i = 1; i < size; i++) {
-      uint32_t idx1 = interfaces->GetTypeItem(i).type_idx_;
+      dex::TypeIndex idx1 = interfaces->GetTypeItem(i).type_idx_;
       for (uint32_t j =0; j < i; j++) {
-        uint32_t idx2 = interfaces->GetTypeItem(j).type_idx_;
+        dex::TypeIndex idx2 = interfaces->GetTypeItem(j).type_idx_;
         if (UNLIKELY(idx1 == idx2)) {
           ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1));
           return false;
@@ -2080,11 +2084,12 @@
   if (item->class_data_off_ != 0) {
     const uint8_t* data = begin_ + item->class_data_off_;
     bool success;
-    uint16_t data_definer = FindFirstClassDataDefiner(data, &success);
+    dex::TypeIndex data_definer = FindFirstClassDataDefiner(data, &success);
     if (!success) {
       return false;
     }
-    if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
+    if (UNLIKELY((data_definer != item->class_idx_) &&
+                 (data_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
       ErrorStringPrintf("Invalid class_data_item");
       return false;
     }
@@ -2099,12 +2104,12 @@
     }
     const uint8_t* data = begin_ + item->annotations_off_;
     bool success;
-    uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
+    dex::TypeIndex annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
     if (!success) {
       return false;
     }
     if (UNLIKELY((annotations_definer != item->class_idx_) &&
-                 (annotations_definer != DexFile::kDexNoIndex16))) {
+                 (annotations_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
       ErrorStringPrintf("Invalid annotations_directory_item");
       return false;
     }
@@ -2165,7 +2170,7 @@
 bool DexFileVerifier::CheckInterClassDataItem() {
   ClassDataItemIterator it(*dex_file_, ptr_);
   bool success;
-  uint16_t defining_class = FindFirstClassDataDefiner(ptr_, &success);
+  dex::TypeIndex defining_class = FindFirstClassDataDefiner(ptr_, &success);
   if (!success) {
     return false;
   }
@@ -2197,7 +2202,7 @@
   const DexFile::AnnotationsDirectoryItem* item =
       reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
   bool success;
-  uint16_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
+  dex::TypeIndex defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
   if (!success) {
     return false;
   }
@@ -2471,15 +2476,15 @@
 
 static std::string GetClassOrError(const uint8_t* const begin,
                                    const DexFile::Header* const header,
-                                   uint32_t class_idx) {
+                                   dex::TypeIndex class_idx) {
   // The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and
   // it has already been checked in `DexFileVerifier::CheckClassDataItemField()`
   // or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match
   // a valid defining class.
-  CHECK_LT(class_idx, header->type_ids_size_);
+  CHECK_LT(class_idx.index_, header->type_ids_size_);
 
   const DexFile::TypeId* type_id =
-      reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
+      reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx.index_;
 
   // Assume that the data is OK at this point. Type id offsets have been checked at this point.
 
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 133e432..19a89de 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -20,6 +20,7 @@
 #include <unordered_set>
 
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "safe_map.h"
 
 namespace art {
@@ -76,12 +77,12 @@
   bool CheckClassDataItemField(uint32_t idx,
                                uint32_t access_flags,
                                uint32_t class_access_flags,
-                               uint16_t class_type_index,
+                               dex::TypeIndex class_type_index,
                                bool expect_static);
   bool CheckClassDataItemMethod(uint32_t idx,
                                 uint32_t access_flags,
                                 uint32_t class_access_flags,
-                                uint16_t class_type_index,
+                                dex::TypeIndex class_type_index,
                                 uint32_t code_offset,
                                 std::unordered_set<uint32_t>* direct_method_indexes,
                                 bool expect_direct);
@@ -90,7 +91,7 @@
                                   uint32_t curr_index,
                                   uint32_t prev_index,
                                   bool* have_class,
-                                  uint16_t* class_type_index,
+                                  dex::TypeIndex* class_type_index,
                                   uint32_t* class_access_flags);
 
   bool CheckPadding(size_t offset, uint32_t aligned_offset);
@@ -104,7 +105,7 @@
   template <bool kStatic>
   bool CheckIntraClassDataItemFields(ClassDataItemIterator* it,
                                      bool* have_class,
-                                     uint16_t* class_type_index,
+                                     dex::TypeIndex* class_type_index,
                                      uint32_t* class_access_flags);
   // Check all methods of the given type from the given iterator. Load the class data from the first
   // method, if necessary (and return it), or use the given values.
@@ -112,7 +113,7 @@
   bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
                                       std::unordered_set<uint32_t>* direct_method_indexes,
                                       bool* have_class,
-                                      uint16_t* class_type_index,
+                                      dex::TypeIndex* class_type_index,
                                       uint32_t* class_access_flags);
 
   bool CheckIntraCodeItem();
@@ -130,8 +131,8 @@
 
   // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
   // additional out parameter to signal any errors loading an index.
-  uint16_t FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
-  uint16_t FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
+  dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
+  dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
 
   bool CheckInterStringIdItem();
   bool CheckInterTypeIdItem();
@@ -150,7 +151,7 @@
   // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
   // not. If there is an error, null is returned.
   const char* CheckLoadStringByIdx(uint32_t idx, const char* error_fmt);
-  const char* CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_fmt);
+  const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
 
   // Load a field/method Id by index. Checks whether the index is in bounds, printing the error if
   // not. If there is an error, null is returned.
@@ -168,7 +169,7 @@
   // linear search. The output values should thus be cached by the caller.
   bool FindClassFlags(uint32_t index,
                       bool is_field,
-                      uint16_t* class_type_index,
+                      dex::TypeIndex* class_type_index,
                       uint32_t* class_access_flags);
 
   // Check validity of the given access flags, interpreted for a field in the context of a class
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 3801c22..0e0929f 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -26,6 +26,7 @@
 #include "base/macros.h"
 #include "common_runtime_test.h"
 #include "dex_file-inl.h"
+#include "dex_file_types.h"
 #include "leb128.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-inl.h"
@@ -155,7 +156,7 @@
       "method_id_class_idx",
       [](DexFile* dex_file) {
         DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
-        method_id->class_idx_ = 0xFF;
+        method_id->class_idx_ = dex::TypeIndex(0xFF);
       },
       "could not find declaring class for direct method index 0");
 
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index c766b54..751bd51 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -208,9 +208,9 @@
         case CONST_CLASS:
         case NEW_INSTANCE:
           if (file != nullptr) {
-            uint32_t type_idx = VRegB_21c();
-            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyType(type_idx)
-               << " // type@" << type_idx;
+            dex::TypeIndex type_idx(VRegB_21c());
+            os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
+               << file->PrettyType(type_idx) << " // type@" << type_idx;
             break;
           }
           FALLTHROUGH_INTENDED;
@@ -302,17 +302,19 @@
           FALLTHROUGH_INTENDED;
         case INSTANCE_OF:
           if (file != nullptr) {
-            uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
-               << file->PrettyType(type_idx) << " // type@" << type_idx;
+            dex::TypeIndex type_idx(VRegC_22c());
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+               << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+               << " // type@" << type_idx.index_;
             break;
           }
           FALLTHROUGH_INTENDED;
         case NEW_ARRAY:
           if (file != nullptr) {
-            uint32_t type_idx = VRegC_22c();
-            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
-               << file->PrettyType(type_idx) << " // type@" << type_idx;
+            dex::TypeIndex type_idx(VRegC_22c());
+            os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+               << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+               << " // type@" << type_idx.index_;
             break;
           }
           FALLTHROUGH_INTENDED;
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index ed60f59..ac52f4e 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -129,7 +129,7 @@
 
 template <const bool kAccessCheck>
 ALWAYS_INLINE
-inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
                                        ArtMethod* method,
                                        Thread* self,
                                        bool* slow_path) {
@@ -219,7 +219,7 @@
 // check.
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
                                            ArtMethod* method,
                                            Thread* self,
                                            gc::AllocatorType allocator_type) {
@@ -275,7 +275,7 @@
 
 template <bool kAccessCheck>
 ALWAYS_INLINE
-inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
                                       int32_t component_count,
                                       ArtMethod* method,
                                       bool* slow_path) {
@@ -313,7 +313,7 @@
 // check.
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE
-inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
                                          int32_t component_count,
                                          ArtMethod* method,
                                          Thread* self,
@@ -562,7 +562,7 @@
       StackHandleScope<2> hs2(self);
       HandleWrapperObjPtr<mirror::Object> h_this(hs2.NewHandleWrapper(this_object));
       Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
-      const uint16_t method_type_idx =
+      const dex::TypeIndex method_type_idx =
           h_referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
       mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
       if (UNLIKELY(method_reference_class == nullptr)) {
@@ -758,7 +758,8 @@
     return resolved_method;
   } else if (type == kSuper) {
     // TODO This lookup is rather slow.
-    uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+    dex::TypeIndex method_type_idx =
+        referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
     mirror::Class* method_reference_class =
         referring_class->GetDexCache()->GetResolvedType(method_type_idx);
     if (method_reference_class == nullptr) {
@@ -788,8 +789,11 @@
   }
 }
 
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, ArtMethod* referrer, Thread* self,
-                                             bool can_run_clinit, bool verify_access) {
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
+                                             ArtMethod* referrer,
+                                             Thread* self,
+                                             bool can_run_clinit,
+                                             bool verify_access) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
   if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 1ccb4b0..5390165 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -38,7 +38,7 @@
 
 namespace art {
 
-static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
+static inline mirror::Class* CheckFilledNewArrayAlloc(dex::TypeIndex type_idx,
                                                       int32_t component_count,
                                                       ArtMethod* referrer,
                                                       Thread* self,
@@ -82,10 +82,12 @@
 }
 
 // Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
-                                          ArtMethod* referrer, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+                                          int32_t component_count,
+                                          ArtMethod* referrer,
+                                          Thread* self,
                                           bool access_check,
-                                          gc::AllocatorType /* allocator_type */) {
+                                          gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
   mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
                                                   access_check);
   if (UNLIKELY(klass == nullptr)) {
@@ -101,12 +103,13 @@
 }
 
 // Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
-                                                      int32_t component_count,
-                                                      ArtMethod* referrer,
-                                                      Thread* self,
-                                                      bool access_check,
-                                                      gc::AllocatorType /* allocator_type */) {
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(
+    dex::TypeIndex type_idx,
+    int32_t component_count,
+    ArtMethod* referrer,
+    Thread* self,
+    bool access_check,
+    gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
   mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
                                                   access_check);
   if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index bcddfb0..d87dc67 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "dex_instruction.h"
+#include "dex_file_types.h"
 #include "gc/allocator_type.h"
 #include "handle.h"
 #include "invoke_type.h"
@@ -45,7 +46,7 @@
 class Thread;
 
 template <const bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
                                                      ArtMethod* method,
                                                      Thread* self,
                                                      bool* slow_path)
@@ -63,7 +64,7 @@
 // When verification/compiler hasn't been able to verify access, optionally perform an access
 // check.
 template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
                                                          ArtMethod* method,
                                                          Thread* self,
                                                          gc::AllocatorType allocator_type)
@@ -89,7 +90,7 @@
 
 
 template <bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
                                                     int32_t component_count,
                                                     ArtMethod* method,
                                                     bool* slow_path)
@@ -101,7 +102,7 @@
 // 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(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
                                                        int32_t component_count,
                                                        ArtMethod* method,
                                                        Thread* self,
@@ -118,19 +119,21 @@
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
-extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
-                                                 ArtMethod* method, Thread* self,
-                                                 bool access_check,
-                                                 gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+                                          int32_t component_count,
+                                          ArtMethod* method,
+                                          Thread* self,
+                                          bool access_check,
+                                          gc::AllocatorType allocator_type)
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
-extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
-                                                             int32_t component_count,
-                                                             ArtMethod* method,
-                                                             Thread* self,
-                                                             bool access_check,
-                                                             gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex type_idx,
+                                                      int32_t component_count,
+                                                      ArtMethod* method,
+                                                      Thread* self,
+                                                      bool access_check,
+                                                      gc::AllocatorType allocator_type)
     REQUIRES_SHARED(Locks::mutator_lock_)
     REQUIRES(!Roles::uninterruptible_);
 
@@ -177,7 +180,7 @@
                                  InvokeType type)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
                                              ArtMethod* referrer,
                                              Thread* self,
                                              bool can_run_clinit,
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 515fcbf..397655a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -19,6 +19,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "callee_save_frame.h"
+#include "dex_file_types.h"
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object_array-inl.h"
@@ -34,7 +35,8 @@
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
   if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
-    mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, kRuntimePointerSize); \
+    mirror::Class* klass = method->GetDexCacheResolvedType<false>(dex::TypeIndex(type_idx), \
+                                                                  kRuntimePointerSize); \
     if (LIKELY(klass != nullptr && klass->IsInitialized() && !klass->IsFinalizable())) { \
       size_t byte_count = klass->GetObjectSize(); \
       byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
@@ -51,7 +53,10 @@
       } \
     } \
   } \
-  return AllocObjectFromCode<false, instrumented_bool>(type_idx, method, self, allocator_type); \
+  return AllocObjectFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+                                                       method, \
+                                                       self, \
+                                                       allocator_type); \
 } \
 extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \
     mirror::Class* klass, ArtMethod* method ATTRIBUTE_UNUSED, Thread* self) \
@@ -101,13 +106,19 @@
     uint32_t type_idx, ArtMethod* method, Thread* self) \
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
-  return AllocObjectFromCode<true, instrumented_bool>(type_idx, method, self, allocator_type); \
+  return AllocObjectFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+                                                      method, \
+                                                      self, \
+                                                      allocator_type); \
 } \
 extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
     uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
-  return AllocArrayFromCode<false, instrumented_bool>(type_idx, component_count, method, self, \
+  return AllocArrayFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+                                                      component_count, \
+                                                      method, \
+                                                      self, \
                                                       allocator_type); \
 } \
 extern "C" mirror::Array* artAllocArrayFromCodeResolved##suffix##suffix2( \
@@ -121,7 +132,10 @@
     uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
-  return AllocArrayFromCode<true, instrumented_bool>(type_idx, component_count, method, self, \
+  return AllocArrayFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+                                                     component_count, \
+                                                     method, \
+                                                     self, \
                                                      allocator_type); \
 } \
 extern "C" mirror::Array* artCheckAndAllocArrayFromCode##suffix##suffix2( \
@@ -129,9 +143,19 @@
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
   if (!(instrumented_bool)) { \
-    return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, false, allocator_type); \
+    return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+                                      component_count, \
+                                      method, \
+                                      self, \
+                                      false, \
+                                      allocator_type); \
   } else { \
-    return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, false, allocator_type); \
+    return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+                                                  component_count, \
+                                                  method, \
+                                                  self, \
+                                                  false, \
+                                                  allocator_type); \
   } \
 } \
 extern "C" mirror::Array* artCheckAndAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
@@ -139,9 +163,19 @@
     REQUIRES_SHARED(Locks::mutator_lock_) { \
   ScopedQuickEntrypointChecks sqec(self); \
   if (!(instrumented_bool)) { \
-    return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, true, allocator_type); \
+    return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+                                      component_count, \
+                                      method, \
+                                      self, \
+                                      true, \
+                                      allocator_type); \
   } else { \
-    return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, true, allocator_type); \
+    return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+                                                  component_count, \
+                                                  method, \
+                                                  self, \
+                                                  true, \
+                                                  allocator_type); \
   } \
 } \
 extern "C" mirror::String* artAllocStringFromBytesFromCode##suffix##suffix2( \
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index d438418..b1259e1 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -20,6 +20,7 @@
 #include "class_linker-inl.h"
 #include "class_table-inl.h"
 #include "dex_file-inl.h"
+#include "dex_file_types.h"
 #include "gc/heap.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
@@ -37,7 +38,7 @@
   // given by inheritance.
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
-  return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
+  return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, true, false);
 }
 
 extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
@@ -45,7 +46,7 @@
   // Called when method->dex_cache_resolved_types_[] misses.
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
-  return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
+  return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, false);
 }
 
 extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
@@ -54,7 +55,7 @@
   // unpopulated.
   ScopedQuickEntrypointChecks sqec(self);
   auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
-  return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
+  return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, true);
 }
 
 extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index a32c800..1b3d339 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -543,7 +543,7 @@
           ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
           // This is a suspend point. But it's ok since value has been set into shadow_frame.
           ObjPtr<mirror::Class> klass = class_linker->ResolveType(
-              instr->VRegB_21c(), shadow_frame->GetMethod());
+              dex::TypeIndex(instr->VRegB_21c()), shadow_frame->GetMethod());
           DCHECK(klass->IsStringClass());
         }
       } else {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 8c63a9e..05f74d6 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1460,7 +1460,7 @@
           ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
           if (do_assignability_check && o != nullptr) {
             PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-            const uint32_t type_idx = params->GetTypeItem(shorty_pos).type_idx_;
+            const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
             ObjPtr<mirror::Class> arg_type = method->GetDexCacheResolvedType(type_idx,
                                                                              pointer_size);
             if (arg_type == nullptr) {
@@ -1568,7 +1568,7 @@
     return false;
   }
   uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
-  ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(type_idx,
+  ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
                                                              shadow_frame.GetMethod(),
                                                              self,
                                                              false,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 435ac62..989b7da 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -395,7 +395,7 @@
       }
       case Instruction::CONST_CLASS: {
         PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
                                                          shadow_frame.GetMethod(),
                                                          self,
                                                          false,
@@ -434,7 +434,7 @@
       }
       case Instruction::CHECK_CAST: {
         PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
                                                          shadow_frame.GetMethod(),
                                                          self,
                                                          false,
@@ -454,7 +454,7 @@
       }
       case Instruction::INSTANCE_OF: {
         PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegC_22c(),
+        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
                                                          shadow_frame.GetMethod(),
                                                          self,
                                                          false,
@@ -484,7 +484,7 @@
       case Instruction::NEW_INSTANCE: {
         PREAMBLE();
         ObjPtr<mirror::Object> obj = nullptr;
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
                                                          shadow_frame.GetMethod(),
                                                          self,
                                                          false,
@@ -495,8 +495,10 @@
             obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
           } else {
             obj = AllocObjectFromCode<do_access_check, true>(
-              inst->VRegB_21c(), shadow_frame.GetMethod(), self,
-              Runtime::Current()->GetHeap()->GetCurrentAllocator());
+                dex::TypeIndex(inst->VRegB_21c()),
+                shadow_frame.GetMethod(),
+                self,
+                Runtime::Current()->GetHeap()->GetCurrentAllocator());
           }
         }
         if (UNLIKELY(obj == nullptr)) {
@@ -520,7 +522,10 @@
         PREAMBLE();
         int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
         ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
-            inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
+            dex::TypeIndex(inst->VRegC_22c()),
+            length,
+            shadow_frame.GetMethod(),
+            self,
             Runtime::Current()->GetHeap()->GetCurrentAllocator());
         if (UNLIKELY(obj == nullptr)) {
           HANDLE_PENDING_EXCEPTION();
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 2bd47bb..fbfed40 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -304,7 +304,11 @@
                                   ShadowFrame* shadow_frame,
                                   Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
+  mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+                                            shadow_frame->GetMethod(),
+                                            self,
+                                            false,
+                                            false);
   if (UNLIKELY(c == nullptr)) {
     return true;
   }
@@ -317,7 +321,11 @@
                                  art::ArtMethod* method,
                                  Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+  ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+                                                   method,
+                                                   self,
+                                                   false,
+                                                   false);
   if (UNLIKELY(c == nullptr)) {
     return true;
   }
@@ -335,7 +343,11 @@
                                   art::ArtMethod* method,
                                   Thread* self)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+  ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+                                                   method,
+                                                   self,
+                                                   false,
+                                                   false);
   if (UNLIKELY(c == nullptr)) {
     return false;  // Caller will check for pending exception.  Return value unimportant.
   }
@@ -353,7 +365,7 @@
     REQUIRES_SHARED(Locks::mutator_lock_) {
   const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
   mirror::Object* obj = nullptr;
-  mirror::Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+  mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
                                             shadow_frame->GetMethod(),
                                             self,
                                             false,
@@ -363,9 +375,10 @@
       gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
       obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
     } else {
-      obj = AllocObjectFromCode<false, true>(
-        inst->VRegB_21c(), shadow_frame->GetMethod(), self,
-        Runtime::Current()->GetHeap()->GetCurrentAllocator());
+      obj = AllocObjectFromCode<false, true>(dex::TypeIndex(inst->VRegB_21c()),
+                                             shadow_frame->GetMethod(),
+                                             self,
+                                             Runtime::Current()->GetHeap()->GetCurrentAllocator());
     }
   }
   if (UNLIKELY(obj == nullptr)) {
@@ -446,7 +459,7 @@
   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>(
-      inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
+      dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
       Runtime::Current()->GetHeap()->GetCurrentAllocator());
   if (UNLIKELY(obj == nullptr)) {
       return false;
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index b9f5981..6f2a8c6 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -235,7 +235,7 @@
       AddUintToBuffer(&buffer, method_it);
     }
     for (auto class_id : dex_data.class_set) {
-      AddUintToBuffer(&buffer, class_id);
+      AddUintToBuffer(&buffer, class_id.index_);
     }
     DCHECK_EQ(required_capacity, buffer.size())
         << "Failed to add the expected number of bytes in the buffer";
@@ -282,7 +282,7 @@
 
 bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
                                            uint32_t checksum,
-                                           uint16_t type_idx) {
+                                           dex::TypeIndex type_idx) {
   DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
   if (data == nullptr) {
     return false;
@@ -305,7 +305,7 @@
 
   for (uint16_t i = 0; i < class_set_size; i++) {
     uint16_t type_idx = line_buffer.ReadUintAndAdvance<uint16_t>();
-    if (!AddClassIndex(dex_location, checksum, type_idx)) {
+    if (!AddClassIndex(dex_location, checksum, dex::TypeIndex(type_idx))) {
       return false;
     }
   }
@@ -569,13 +569,13 @@
   return false;
 }
 
-bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, uint16_t type_idx) const {
+bool ProfileCompilationInfo::ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const {
   auto info_it = info_.find(GetProfileDexFileKey(dex_file.GetLocation()));
   if (info_it != info_.end()) {
     if (!ChecksumMatch(dex_file, info_it->second.checksum)) {
       return false;
     }
-    const std::set<uint16_t>& classes = info_it->second.class_set;
+    const std::set<dex::TypeIndex>& classes = info_it->second.class_set;
     return classes.find(type_idx) != classes.end();
   }
   return false;
@@ -706,7 +706,7 @@
       if (c < (number_of_classes / kFavorSplit)) {
         type_idx %= kFavorFirstN;
       }
-      info.AddClassIndex(profile_key, 0, type_idx);
+      info.AddClassIndex(profile_key, 0, dex::TypeIndex(type_idx));
     }
   }
   return info.Save(fd);
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index f8ed573..4136488 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -23,6 +23,7 @@
 #include "atomic.h"
 #include "dex_cache_resolved_classes.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "method_reference.h"
 #include "safe_map.h"
 
@@ -66,7 +67,7 @@
   bool ContainsMethod(const MethodReference& method_ref) const;
 
   // Returns true if the class's type is present in the profiling info.
-  bool ContainsClass(const DexFile& dex_file, uint16_t type_idx) const;
+  bool ContainsClass(const DexFile& dex_file, dex::TypeIndex type_idx) const;
 
   // Dumps all the loaded profile info into a string and returns it.
   // If dex_files is not null then the method indices will be resolved to their
@@ -104,7 +105,7 @@
     explicit DexFileData(uint32_t location_checksum) : checksum(location_checksum) {}
     uint32_t checksum;
     std::set<uint16_t> method_set;
-    std::set<uint16_t> class_set;
+    std::set<dex::TypeIndex> class_set;
 
     bool operator==(const DexFileData& other) const {
       return checksum == other.checksum && method_set == other.method_set;
@@ -115,7 +116,7 @@
 
   DexFileData* GetOrAddDexFileData(const std::string& dex_location, uint32_t checksum);
   bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
-  bool AddClassIndex(const std::string& dex_location, uint32_t checksum, uint16_t type_idx);
+  bool AddClassIndex(const std::string& dex_location, uint32_t checksum, dex::TypeIndex type_idx);
   bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
 
   // Parsing functionality.
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 9a6d60e..aa5da2e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -372,7 +372,7 @@
     // to access the field if the FieldId specifies an accessible subclass of the declaring
     // class rather than the declaring class itself.
     ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
-    uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
+    dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
     // The referenced class has already been resolved with the field, but may not be in the dex
     // cache. Use LookupResolveType here to search the class table if it is not in the dex cache.
     // should be no thread suspension due to the class being resolved.
@@ -410,7 +410,7 @@
     // to access the method if the MethodId specifies an accessible subclass of the declaring
     // class rather than the declaring class itself.
     ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
-    uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
+    dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
     // The referenced class has already been resolved with the method, but may not be in the dex
     // cache.
     ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
@@ -894,7 +894,8 @@
   klass->SetClassSize(class_size_);
   klass->SetPrimitiveType(Primitive::kPrimNot);  // Default to not being primitive.
   klass->SetDexClassDefIndex(DexFile::kDexNoIndex16);  // Default to no valid class def index.
-  klass->SetDexTypeIndex(DexFile::kDexNoIndex16);  // Default to no valid type index.
+  klass->SetDexTypeIndex(dex::TypeIndex(DexFile::kDexNoIndex16));  // Default to no valid type
+                                                                   // index.
   // Default to force slow path until initialized.
   klass->SetObjectSizeAllocFastPath(std::numeric_limits<uint32_t>::max());
 }
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index db46027..0cfe29b 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -923,7 +923,7 @@
   return &GetDexFile().GetClassDef(class_def_idx);
 }
 
-uint16_t Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
+dex::TypeIndex Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
   DCHECK(!IsPrimitive());
   DCHECK(!IsArrayClass());
   return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
@@ -947,10 +947,11 @@
     DCHECK(interfaces != nullptr);
     return interfaces->Get(idx);
   } else {
-    uint16_t type_idx = klass->GetDirectInterfaceTypeIdx(idx);
+    dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
     ObjPtr<Class> interface = klass->GetDexCache()->GetResolvedType(type_idx);
     if (interface == nullptr) {
-      interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(), type_idx,
+      interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(),
+                                                                    type_idx,
                                                                     klass.Get());
       CHECK(interface != nullptr || self->IsExceptionPending());
     }
@@ -1130,10 +1131,12 @@
   return depth;
 }
 
-uint32_t Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
+dex::TypeIndex Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
   std::string temp;
   const DexFile::TypeId* type_id = dex_file.FindTypeId(GetDescriptor(&temp));
-  return (type_id == nullptr) ? DexFile::kDexNoIndex : dex_file.GetIndexForTypeId(*type_id);
+  return (type_id == nullptr)
+      ? dex::TypeIndex(DexFile::kDexNoIndex)
+      : dex_file.GetIndexForTypeId(*type_id);
 }
 
 template <PointerSize kPointerSize, bool kTransactionActive>
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 711914d..792f626 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -20,6 +20,7 @@
 #include "base/enums.h"
 #include "base/iteration_range.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "class_flags.h"
 #include "gc_root.h"
 #include "gc/allocator_type.h"
@@ -1148,16 +1149,17 @@
     SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx);
   }
 
-  uint16_t GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_));
+  dex::TypeIndex GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return dex::TypeIndex(
+        static_cast<uint16_t>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_))));
   }
 
-  void SetDexTypeIndex(uint16_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
+  void SetDexTypeIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
     // Not called within a transaction.
-    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx);
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx.index_);
   }
 
-  uint32_t FindTypeIndexInOtherDexFile(const DexFile& dex_file)
+  dex::TypeIndex FindTypeIndexInOtherDexFile(const DexFile& dex_file)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   static Class* GetJavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1198,7 +1200,7 @@
 
   ALWAYS_INLINE uint32_t NumDirectInterfaces() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  dex::TypeIndex GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
   static ObjPtr<Class> GetDirectInterface(Thread* self,
                                           Handle<Class> klass,
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index c7a123b..d903f71 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -69,15 +69,15 @@
   }
 }
 
-inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
-  DCHECK_LT(type_idx, NumResolvedTypes());
-  return GetResolvedTypes()[type_idx].Read();
+inline Class* DexCache::GetResolvedType(dex::TypeIndex type_idx) {
+  DCHECK_LT(type_idx.index_, NumResolvedTypes());
+  return GetResolvedTypes()[type_idx.index_].Read();
 }
 
-inline void DexCache::SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved) {
-  DCHECK_LT(type_idx, NumResolvedTypes());  // NOTE: Unchecked, i.e. not throwing AIOOB.
+inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
+  DCHECK_LT(type_idx.index_, NumResolvedTypes());  // NOTE: Unchecked, i.e. not throwing AIOOB.
   // TODO default transaction support.
-  GetResolvedTypes()[type_idx] = GcRoot<Class>(resolved);
+  GetResolvedTypes()[type_idx.index_] = GcRoot<Class>(resolved);
   // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
   Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
 }
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 1ae694d..7d82d3a 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -21,6 +21,7 @@
 #include "art_field.h"
 #include "art_method.h"
 #include "class.h"
+#include "dex_file_types.h"
 #include "object.h"
 #include "object_array.h"
 
@@ -223,9 +224,9 @@
   // the string isn't kept live.
   void ClearString(uint32_t string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  Class* GetResolvedType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+  Class* GetResolvedType(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved)
+  void SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE ArtMethod* GetResolvedMethod(uint32_t method_idx, PointerSize ptr_size)
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 5bf254d..4b47f7f 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -313,7 +313,7 @@
   ArtMethod* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V", kRuntimePointerSize);
   const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId("[I");
   ASSERT_TRUE(type_id != nullptr);
-  uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
+  dex::TypeIndex type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
   Object* array = CheckAndAllocArrayFromCodeInstrumented(
       type_idx, 3, sort, Thread::Current(), false,
       Runtime::Current()->GetHeap()->GetCurrentAllocator());
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index b866a63..ade4e87 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -104,7 +104,7 @@
     CHECK_EQ(array_len % 2, 0);
     const auto depth = array_len / 2;
     if (depth == 0) {
-      result += "(Throwable with empty stack trace)";
+      result += "(Throwable with empty stack trace)\n";
     } else {
       const PointerSize ptr_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
       for (int32_t i = 0; i < depth; ++i) {
@@ -124,7 +124,7 @@
       ObjPtr<ObjectArray<StackTraceElement>> ste_array =
           ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace);
       if (ste_array->GetLength() == 0) {
-        result += "(Throwable with empty stack trace)";
+        result += "(Throwable with empty stack trace)\n";
       } else {
         for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
           StackTraceElement* ste = ste_array->Get(i);
@@ -139,7 +139,7 @@
         }
       }
     } else {
-      result += "(Throwable with no stack trace)";
+      result += "(Throwable with no stack trace)\n";
     }
   }
   ObjPtr<Throwable> cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 866dc7f..48feb11 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -34,6 +34,7 @@
 #include "common_throws.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "dex_file_types.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/allocator/dlmalloc.h"
 #include "gc/heap.h"
@@ -305,7 +306,7 @@
 // Based on ClassLinker::ResolveType.
 static void PreloadDexCachesResolveType(Thread* self,
                                         ObjPtr<mirror::DexCache> dex_cache,
-                                        uint32_t type_idx)
+                                        dex::TypeIndex type_idx)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(type_idx);
   if (klass != nullptr) {
@@ -455,7 +456,7 @@
       }
     }
     for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
-      ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(j);
+      ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(j));
       if (klass != nullptr) {
         filled->num_types++;
       }
@@ -519,7 +520,7 @@
 
     if (kPreloadDexCachesTypes) {
       for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
-        PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), j);
+        PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), dex::TypeIndex(j));
       }
     }
 
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index 71379a5..f6de593 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -17,6 +17,7 @@
 #include "java_lang_DexCache.h"
 
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
@@ -53,7 +54,7 @@
   ScopedFastNativeObjectAccess soa(env);
   ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
-  return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
+  return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(dex::TypeIndex(type_index)));
 }
 
 static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
@@ -68,7 +69,7 @@
   ScopedFastNativeObjectAccess soa(env);
   ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
   CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
-  dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type));
+  dex_cache->SetResolvedType(dex::TypeIndex(type_index), soa.Decode<mirror::Class>(type));
 }
 
 static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index c14b616..404e5ce 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -38,6 +38,7 @@
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
+#include "dex_file_types.h"
 #include "elf_file.h"
 #include "elf_utils.h"
 #include "gc_root.h"
@@ -1252,13 +1253,14 @@
     if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) > GetOatFile()->End()) {
       LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
     } else {
-      lookup_table_.reset(TypeLookupTable::Open(dex_file_pointer_,
-                                                lookup_table_data_,
-                                                num_class_defs));
+      lookup_table_ = TypeLookupTable::Open(dex_file_pointer_, lookup_table_data_, num_class_defs);
     }
   }
 }
 
+OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table)
+    : lookup_table_(std::move(lookup_table)) {}
+
 OatFile::OatDexFile::~OatDexFile() {}
 
 size_t OatFile::OatDexFile::FileSize() const {
@@ -1342,7 +1344,7 @@
   }
   const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
   if (type_id != nullptr) {
-    uint16_t type_idx = dex_file.GetIndexForTypeId(*type_id);
+    dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
     return dex_file.FindClassDef(type_idx);
   }
   return nullptr;
@@ -1540,7 +1542,7 @@
                                         bool* found) {
   DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
   const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
-  if (oat_dex_file == nullptr) {
+  if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
     *found = false;
     return OatFile::OatClass::Invalid();
   }
@@ -1548,4 +1550,8 @@
   return oat_dex_file->GetOatClass(class_def_idx);
 }
 
+void OatFile::OatDexFile::AssertAotCompiler() {
+  CHECK(Runtime::Current()->IsAotCompiler());
+}
+
 }  // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 63a0e14..29add5b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -384,7 +384,13 @@
   // Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
   std::unique_ptr<const DexFile> OpenDexFile(std::string* error_msg) const;
 
+  // May return null if the OatDexFile only contains a type lookup table. This case only happens
+  // for the compiler to speed up compilation.
   const OatFile* GetOatFile() const {
+    // Avoid pulling in runtime.h in the header file.
+    if (kIsDebugBuild && oat_file_ == nullptr) {
+      AssertAotCompiler();
+    }
     return oat_file_;
   }
 
@@ -436,6 +442,9 @@
 
   ~OatDexFile();
 
+  // Create only with a type lookup table, used by the compiler to speed up compilation.
+  explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);
+
  private:
   OatDexFile(const OatFile* oat_file,
              const std::string& dex_file_location,
@@ -446,14 +455,16 @@
              const uint32_t* oat_class_offsets_pointer,
              uint8_t* dex_cache_arrays);
 
-  const OatFile* const oat_file_;
+  static void AssertAotCompiler();
+
+  const OatFile* const oat_file_ = nullptr;
   const std::string dex_file_location_;
   const std::string canonical_dex_file_location_;
-  const uint32_t dex_file_location_checksum_;
-  const uint8_t* const dex_file_pointer_;
-  const uint8_t* lookup_table_data_;
-  const uint32_t* const oat_class_offsets_pointer_;
-  uint8_t* const dex_cache_arrays_;
+  const uint32_t dex_file_location_checksum_ = 0u;
+  const uint8_t* const dex_file_pointer_ = nullptr;
+  const uint8_t* lookup_table_data_ = nullptr;
+  const uint32_t* const oat_class_offsets_pointer_ = 0u;
+  uint8_t* const dex_cache_arrays_ = nullptr;
   mutable std::unique_ptr<TypeLookupTable> lookup_table_;
 
   friend class OatFile;
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 0eff469..5e588a8 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -269,6 +269,12 @@
       ReportRoot(root_obj, info);
     }
 
+    // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly.
+    art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS {
+      art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current());
+      return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId());
+    }
+
     jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info,
                                             jvmtiHeapReferenceInfo* ref_info)
         REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -280,7 +286,34 @@
           return JVMTI_HEAP_REFERENCE_JNI_GLOBAL;
 
         case art::RootType::kRootJNILocal:
+        {
+          uint32_t thread_id = info.GetThreadId();
+          ref_info->jni_local.thread_id = thread_id;
+
+          art::Thread* thread = FindThread(info);
+          if (thread != nullptr) {
+            art::mirror::Object* thread_obj = thread->GetPeer();
+            if (thread->IsStillStarting()) {
+              thread_obj = nullptr;
+            } else {
+              thread_obj = thread->GetPeer();
+            }
+            if (thread_obj != nullptr) {
+              ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
+            }
+          }
+
+          // TODO: We don't have this info.
+          if (thread != nullptr) {
+            ref_info->jni_local.depth = 0;
+            art::ArtMethod* method = thread->GetCurrentMethod(nullptr, false /* abort_on_error */);
+            if (method != nullptr) {
+              ref_info->jni_local.method = art::jni::EncodeArtMethod(method);
+            }
+          }
+
           return JVMTI_HEAP_REFERENCE_JNI_LOCAL;
+        }
 
         case art::RootType::kRootJavaFrame:
           return JVMTI_HEAP_REFERENCE_STACK_LOCAL;
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index e391a9d..ffa5ac7 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -78,7 +78,9 @@
   }
 
   // TODO: Support generic signature.
-  *generic_ptr = nullptr;
+  if (generic_ptr != nullptr) {
+    *generic_ptr = nullptr;
+  }
 
   // Everything is fine, release the buffers.
   name_copy.release();
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index fa2983c..7bb5205 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -33,6 +33,7 @@
 
 #include "class_linker.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "gc_root-inl.h"
 #include "globals.h"
 #include "jni_env_ext-inl.h"
@@ -108,10 +109,10 @@
     // Find the code_item for the method then find the dex_method_index and dex_code_item_offset to
     // set.
     const art::DexFile::StringId* new_name_id = dex_file->FindStringId(method.GetName());
-    uint16_t method_return_idx =
+    art::dex::TypeIndex method_return_idx =
         dex_file->GetIndexForTypeId(*dex_file->FindTypeId(method.GetReturnTypeDescriptor()));
     const auto* old_type_list = method.GetParameterTypeList();
-    std::vector<uint16_t> new_type_list;
+    std::vector<art::dex::TypeIndex> new_type_list;
     for (uint32_t i = 0; old_type_list != nullptr && i < old_type_list->Size(); i++) {
       new_type_list.push_back(
           dex_file->GetIndexForTypeId(
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 3128380..8446b52 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -363,7 +363,7 @@
   Thread* const self = Thread::Current();
   PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
   for (uint32_t i = 0; i < num_params; i++) {
-    uint16_t type_idx = params->GetTypeItem(i).type_idx_;
+    dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
     ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
                                                               true /* resolve*/,
                                                               pointer_size));
diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 56e9262..16cd722 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -50,17 +50,19 @@
   return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
 }
 
-TypeLookupTable* TypeLookupTable::Create(const DexFile& dex_file, uint8_t* storage) {
+std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file,
+                                                         uint8_t* storage) {
   const uint32_t num_class_defs = dex_file.NumClassDefs();
-  return SupportedSize(num_class_defs)
+  return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs)
       ? new TypeLookupTable(dex_file, storage)
-      : nullptr;
+      : nullptr);
 }
 
-TypeLookupTable* TypeLookupTable::Open(const uint8_t* dex_file_pointer,
-                                       const uint8_t* raw_data,
-                                       uint32_t num_class_defs) {
-  return new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs);
+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)
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 9595743..3f6f76f 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -60,13 +60,14 @@
   }
 
   // Method creates lookup table for dex file
-  static TypeLookupTable* Create(const DexFile& dex_file, uint8_t* storage = nullptr);
+  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 TypeLookupTable* Open(const uint8_t* dex_file_pointer,
-                               const uint8_t* raw_data,
-                               uint32_t num_class_defs);
+  static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer,
+                                               const uint8_t* raw_data,
+                                               uint32_t num_class_defs);
 
   // Method returns pointer to binary data of lookup table. Used by the oat writer.
   const uint8_t* RawData() const {
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index c7875b5..bd1b044 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -65,8 +65,8 @@
   return PointerSize::k32;
 }
 
-inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const {
-  return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx);
+inline size_t DexCacheArraysLayout::TypeOffset(dex::TypeIndex type_idx) const {
+  return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx.index_);
 }
 
 inline size_t DexCacheArraysLayout::TypesSize(size_t num_elements) const {
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index ae3bfab..7d4b23a 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
 
 #include "dex_file.h"
+#include "dex_file_types.h"
 
 namespace art {
 
@@ -59,7 +60,7 @@
     return types_offset_;
   }
 
-  size_t TypeOffset(uint32_t type_idx) const;
+  size_t TypeOffset(dex::TypeIndex type_idx) const;
 
   size_t TypesSize(size_t num_elements) const;
 
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index def61db..363bd8f 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -74,7 +74,7 @@
   return !failure_messages_.empty();
 }
 
-inline const RegType& MethodVerifier::ResolveCheckedClass(uint32_t class_idx) {
+inline const RegType& MethodVerifier::ResolveCheckedClass(dex::TypeIndex class_idx) {
   DCHECK(!HasFailures());
   const RegType& result = ResolveClassAndCheckAccess(class_idx);
   DCHECK(!HasFailures());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index ed24611..7137db8 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1072,7 +1072,7 @@
       GetInstructionFlags(dex_pc).SetBranchTarget();
       // Ensure exception types are resolved so that they don't need resolution to be delivered,
       // unresolved exception types will be ignored by exception delivery
-      if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+      if (iterator.GetHandlerTypeIndex().IsValid()) {
         mirror::Class* exception_type = linker->ResolveType(*dex_file_,
                                                             iterator.GetHandlerTypeIndex(),
                                                             dex_cache_, class_loader_);
@@ -1155,13 +1155,13 @@
       result = result && CheckMethodIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBNewInstance:
-      result = result && CheckNewInstance(inst->VRegB());
+      result = result && CheckNewInstance(dex::TypeIndex(inst->VRegB()));
       break;
     case Instruction::kVerifyRegBString:
       result = result && CheckStringIndex(inst->VRegB());
       break;
     case Instruction::kVerifyRegBType:
-      result = result && CheckTypeIndex(inst->VRegB());
+      result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegB()));
       break;
     case Instruction::kVerifyRegBWide:
       result = result && CheckWideRegisterIndex(inst->VRegB());
@@ -1175,10 +1175,10 @@
       result = result && CheckFieldIndex(inst->VRegC());
       break;
     case Instruction::kVerifyRegCNewArray:
-      result = result && CheckNewArray(inst->VRegC());
+      result = result && CheckNewArray(dex::TypeIndex(inst->VRegC()));
       break;
     case Instruction::kVerifyRegCType:
-      result = result && CheckTypeIndex(inst->VRegC());
+      result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegC()));
       break;
     case Instruction::kVerifyRegCWide:
       result = result && CheckWideRegisterIndex(inst->VRegC());
@@ -1270,9 +1270,9 @@
   return true;
 }
 
-inline bool MethodVerifier::CheckNewInstance(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().type_ids_size_) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) {
+  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
   }
@@ -1298,18 +1298,18 @@
   return true;
 }
 
-inline bool MethodVerifier::CheckTypeIndex(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().type_ids_size_) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckTypeIndex(dex::TypeIndex idx) {
+  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
   }
   return true;
 }
 
-bool MethodVerifier::CheckNewArray(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().type_ids_size_) {
-    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+bool MethodVerifier::CheckNewArray(dex::TypeIndex idx) {
+  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+    Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
   }
@@ -1945,7 +1945,7 @@
 
 // Returns the index of the first final instance field of the given class, or kDexNoIndex if there
 // is no such field.
-static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, uint16_t type_idx) {
+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);
@@ -2293,7 +2293,7 @@
     case Instruction::CONST_CLASS: {
       // Get type from instruction if unresolved then we need an access check
       // TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
-      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+      const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
       // Register holds class, ie its type is class, on error it will hold Conflict.
       work_line_->SetRegisterType<LockOp::kClear>(
           this, inst->VRegA_21c(), res_type.IsConflict() ? res_type
@@ -2363,7 +2363,7 @@
        * dec_insn.vA when branching to a handler.
        */
       const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
-      const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+      const dex::TypeIndex type_idx((is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c());
       const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
       if (res_type.IsConflict()) {
         // If this is a primitive type, fail HARD.
@@ -2433,7 +2433,7 @@
       break;
     }
     case Instruction::NEW_INSTANCE: {
-      const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+      const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
       if (res_type.IsConflict()) {
         DCHECK_NE(failures_.size(), 0U);
         break;  // bad class
@@ -2645,7 +2645,8 @@
         // ensure that subsequent merges don't lose type information - such as becoming an
         // interface from a class that would lose information relevant to field checks.
         const RegType& orig_type = work_line_->GetRegisterType(this, instance_of_inst->VRegB_22c());
-        const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+        const RegType& cast_type = ResolveClassAndCheckAccess(
+            dex::TypeIndex(instance_of_inst->VRegC_22c()));
 
         if (!orig_type.Equals(cast_type) &&
             !cast_type.IsUnresolvedTypes() && !orig_type.IsUnresolvedTypes() &&
@@ -2883,7 +2884,8 @@
       if (return_type == nullptr) {
         uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-        uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+        dex::TypeIndex return_type_idx =
+            dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
         return_type = &reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
       }
@@ -2906,7 +2908,8 @@
         uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
         is_constructor = strcmp("<init>", dex_file_->StringDataByIdx(method_id.name_idx_)) == 0;
-        uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+        dex::TypeIndex return_type_idx =
+            dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         return_type_descriptor =  dex_file_->StringByTypeIdx(return_type_idx);
       } else {
         is_constructor = called_method->IsConstructor();
@@ -2982,7 +2985,8 @@
         if (called_method == nullptr) {
           uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
           const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-          uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+          dex::TypeIndex return_type_idx =
+              dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
           descriptor = dex_file_->StringByTypeIdx(return_type_idx);
         } else {
           descriptor = called_method->GetReturnTypeDescriptor();
@@ -3036,7 +3040,8 @@
       if (abs_method == nullptr) {
         uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
         const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
-        uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+        dex::TypeIndex return_type_idx =
+            dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
         descriptor = dex_file_->StringByTypeIdx(return_type_idx);
       } else {
         descriptor = abs_method->GetReturnTypeDescriptor();
@@ -3500,8 +3505,8 @@
     ClassLinker* linker = Runtime::Current()->GetClassLinker();
 
     for (; iterator.HasNext(); iterator.Next()) {
-      uint16_t handler_type_idx = iterator.GetHandlerTypeIndex();
-      if (handler_type_idx == DexFile::kDexNoIndex16) {
+      dex::TypeIndex handler_type_idx = iterator.GetHandlerTypeIndex();
+      if (!handler_type_idx.IsValid()) {
         has_catch_all_handler = true;
       } else {
         // It is also a catch-all if it is java.lang.Throwable.
@@ -3628,7 +3633,7 @@
   return klass->IsInstantiable() || klass->IsPrimitive();
 }
 
-const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
+const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) {
   mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
   const RegType* result = nullptr;
   if (klass != nullptr) {
@@ -3684,7 +3689,7 @@
       CatchHandlerIterator iterator(handlers_ptr);
       for (; iterator.HasNext(); iterator.Next()) {
         if (iterator.GetHandlerAddress() == (uint32_t) work_insn_idx_) {
-          if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) {
+          if (!iterator.GetHandlerTypeIndex().IsValid()) {
             common_super = &reg_types_.JavaLangThrowable(false);
           } else {
             const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
@@ -3941,7 +3946,7 @@
                                       klass->CannotBeAssignedFromOtherTypes());
       } else {
         const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-        const uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+        const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
         res_method_class = &reg_types_.FromDescriptor(
             GetClassLoader(),
             dex_file_->StringByTypeIdx(class_idx),
@@ -4078,7 +4083,7 @@
   // If we're using invoke-super(method), make sure that the executing method's class' superclass
   // has a vtable entry for the target method. Or the target is on a interface.
   if (method_type == METHOD_SUPER) {
-    uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+    dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
     const RegType& reference_type = reg_types_.FromDescriptor(
         GetClassLoader(),
         dex_file_->StringByTypeIdx(class_idx),
@@ -4287,16 +4292,16 @@
 }
 
 void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
-  uint32_t type_idx;
+  dex::TypeIndex type_idx;
   if (!is_filled) {
     DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
-    type_idx = inst->VRegC_22c();
+    type_idx = dex::TypeIndex(inst->VRegC_22c());
   } else if (!is_range) {
     DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
-    type_idx = inst->VRegB_35c();
+    type_idx = dex::TypeIndex(inst->VRegB_35c());
   } else {
     DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
-    type_idx = inst->VRegB_3rc();
+    type_idx = dex::TypeIndex(inst->VRegB_3rc());
   }
   const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
   if (res_type.IsConflict()) {  // bad class
@@ -5011,7 +5016,7 @@
     if (return_type_ == nullptr) {
       const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
       const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
-      uint16_t return_type_idx = proto_id.return_type_idx_;
+      dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
       const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
       return_type_ = &reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
     }
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c6ce583..f3faecd 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -27,6 +27,7 @@
 #include "base/stl_util.h"
 #include "base/value_object.h"
 #include "dex_file.h"
+#include "dex_file_types.h"
 #include "handle.h"
 #include "instruction_flags.h"
 #include "method_reference.h"
@@ -261,7 +262,7 @@
     return have_any_pending_runtime_throw_failure_;
   }
 
-  const RegType& ResolveCheckedClass(uint32_t class_idx)
+  const RegType& ResolveCheckedClass(dex::TypeIndex class_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
   // Returns the method of a quick invoke or null if it cannot be found.
   ArtMethod* GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line,
@@ -471,18 +472,18 @@
 
   // Perform static checks on a "new-instance" instruction. Specifically, make sure the class
   // reference isn't for an array class.
-  bool CheckNewInstance(uint32_t idx);
+  bool CheckNewInstance(dex::TypeIndex idx);
 
   /* Ensure that the string index is in the valid range. */
   bool CheckStringIndex(uint32_t idx);
 
   // Perform static checks on an instruction that takes a class constant. Ensure that the class
   // index is in the valid range.
-  bool CheckTypeIndex(uint32_t idx);
+  bool CheckTypeIndex(dex::TypeIndex idx);
 
   // Perform static checks on a "new-array" instruction. Specifically, make sure they aren't
   // creating an array of arrays that causes the number of dimensions to exceed 255.
-  bool CheckNewArray(uint32_t idx);
+  bool CheckNewArray(dex::TypeIndex idx);
 
   // Verify an array data table. "cur_offset" is the offset of the fill-array-data instruction.
   bool CheckArrayData(uint32_t cur_offset);
@@ -625,7 +626,7 @@
 
   // Resolves a class based on an index and performs access checks to ensure the referrer can
   // access the resolved class.
-  const RegType& ResolveClassAndCheckAccess(uint32_t class_idx)
+  const RegType& ResolveClassAndCheckAccess(dex::TypeIndex class_idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   /*
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index c395612d7..a65e82b 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -16,6 +16,8 @@
 
 #include "verifier_deps.h"
 
+#include <cstring>
+
 #include "compiler_callbacks.h"
 #include "leb128.h"
 #include "mirror/class-inl.h"
@@ -56,17 +58,80 @@
   }
 }
 
-template <typename T>
-uint32_t VerifierDeps::GetDeclaringClassStringId(const DexFile& dex_file, T* element) {
+uint32_t VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
+                                                  ObjPtr<mirror::Class> klass) {
+  DCHECK(klass != nullptr);
+  ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
+  // Array classes do not have a dex cache.
+  if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
+    DCHECK(dex_cache != nullptr) << klass->PrettyClass();
+    if (dex_cache->GetDexFile() == &dex_file) {
+      // FindStringId is slow, try to go through the class def if we have one.
+      const DexFile::ClassDef* class_def = klass->GetClassDef();
+      DCHECK(class_def != nullptr) << klass->PrettyClass();
+      std::string temp;
+      const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
+      DCHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
+      return type_id.descriptor_idx_;
+    }
+  }
+  std::string temp;
+  return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
+}
+
+// Try to find the string descriptor of the class. type_idx is a best guess of a matching string id.
+static uint32_t TryGetClassDescriptorStringId(const DexFile& dex_file,
+                                              dex::TypeIndex type_idx,
+                                              ObjPtr<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  if (!klass->IsArrayClass()) {
+    const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
+    const DexFile& klass_dex = klass->GetDexFile();
+    const DexFile::TypeId& klass_type_id = klass_dex.GetTypeId(klass->GetClassDef()->class_idx_);
+    if (strcmp(dex_file.GetTypeDescriptor(type_id),
+               klass_dex.GetTypeDescriptor(klass_type_id)) == 0) {
+      return type_id.descriptor_idx_;
+    }
+  }
+  return DexFile::kDexNoIndex;
+}
+
+uint32_t VerifierDeps::GetMethodDeclaringClassStringId(const DexFile& dex_file,
+                                                       uint32_t dex_method_index,
+                                                       ArtMethod* method) {
   static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
-  if (element == nullptr) {
+  if (method == nullptr) {
     return VerifierDeps::kUnresolvedMarker;
-  } else {
-    std::string temp;
-    uint32_t string_id = GetIdFromString(
-        dex_file, element->GetDeclaringClass()->GetDescriptor(&temp));
+  }
+  const uint32_t string_id = TryGetClassDescriptorStringId(
+      dex_file,
+      dex_file.GetMethodId(dex_method_index).class_idx_,
+      method->GetDeclaringClass());
+  if (string_id != DexFile::kDexNoIndex) {
+    // Got lucky using the original dex file, return based on the input dex file.
+    DCHECK_EQ(GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()), string_id);
     return string_id;
   }
+  return GetClassDescriptorStringId(dex_file, method->GetDeclaringClass());
+}
+
+uint32_t VerifierDeps::GetFieldDeclaringClassStringId(const DexFile& dex_file,
+                                                      uint32_t dex_field_idx,
+                                                      ArtField* field) {
+  static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
+  if (field == nullptr) {
+    return VerifierDeps::kUnresolvedMarker;
+  }
+  const uint32_t string_id = TryGetClassDescriptorStringId(
+      dex_file,
+      dex_file.GetFieldId(dex_field_idx).class_idx_,
+      field->GetDeclaringClass());
+  if (string_id != DexFile::kDexNoIndex) {
+    // Got lucky using the original dex file, return based on the input dex file.
+    DCHECK_EQ(GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()), string_id);
+    return string_id;
+  }
+  return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
 }
 
 uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
@@ -137,7 +202,7 @@
 }
 
 void VerifierDeps::AddClassResolution(const DexFile& dex_file,
-                                      uint16_t type_idx,
+                                      dex::TypeIndex type_idx,
                                       mirror::Class* klass) {
   DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
   if (dex_deps == nullptr) {
@@ -171,8 +236,11 @@
   }
 
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-  dex_deps->fields_.emplace(FieldResolution(
-      field_idx, GetAccessFlags(field), GetDeclaringClassStringId(dex_file, field)));
+  dex_deps->fields_.emplace(FieldResolution(field_idx,
+                                            GetAccessFlags(field),
+                                            GetFieldDeclaringClassStringId(dex_file,
+                                                                           field_idx,
+                                                                           field)));
 }
 
 void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
@@ -194,7 +262,7 @@
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
   MethodResolution method_tuple(method_idx,
                                 GetAccessFlags(method),
-                                GetDeclaringClassStringId(dex_file, method));
+                                GetMethodDeclaringClassStringId(dex_file, method_idx, method));
   if (resolution_kind == kDirectMethodResolution) {
     dex_deps->direct_methods_.emplace(method_tuple);
   } else if (resolution_kind == kVirtualMethodResolution) {
@@ -263,12 +331,8 @@
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
 
   // Get string IDs for both descriptors and store in the appropriate set.
-
-  std::string temp1, temp2;
-  std::string destination_desc(destination->GetDescriptor(&temp1));
-  std::string source_desc(source->GetDescriptor(&temp2));
-  uint32_t destination_id = GetIdFromString(dex_file, destination_desc);
-  uint32_t source_id = GetIdFromString(dex_file, source_desc);
+  uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
+  uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
 
   if (is_assignable) {
     dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
@@ -286,7 +350,7 @@
 }
 
 void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
-                                                 uint16_t type_idx,
+                                                 dex::TypeIndex type_idx,
                                                  MethodVerifier::FailureKind failure_kind) {
   if (failure_kind == MethodVerifier::kNoFailure) {
     // We only record classes that did not fully verify at compile time.
@@ -302,7 +366,7 @@
 }
 
 void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
-                                              uint16_t type_idx,
+                                              dex::TypeIndex type_idx,
                                               mirror::Class* klass) {
   VerifierDeps* singleton = GetVerifierDepsSingleton();
   if (singleton != nullptr) {
@@ -340,36 +404,62 @@
   }
 }
 
+namespace {
+
 static inline uint32_t DecodeUint32WithOverflowCheck(const uint8_t** in, const uint8_t* end) {
   CHECK_LT(*in, end);
   return DecodeUnsignedLeb128(in);
 }
 
+template<typename T> inline uint32_t Encode(T in);
+
+template<> inline uint32_t Encode<uint16_t>(uint16_t in) {
+  return in;
+}
+template<> inline uint32_t Encode<uint32_t>(uint32_t in) {
+  return in;
+}
+template<> inline uint32_t Encode<dex::TypeIndex>(dex::TypeIndex in) {
+  return in.index_;
+}
+
+template<typename T> inline T Decode(uint32_t in);
+
+template<> inline uint16_t Decode<uint16_t>(uint32_t in) {
+  return dchecked_integral_cast<uint16_t>(in);
+}
+template<> inline uint32_t Decode<uint32_t>(uint32_t in) {
+  return in;
+}
+template<> inline dex::TypeIndex Decode<dex::TypeIndex>(uint32_t in) {
+  return dex::TypeIndex(in);
+}
+
 template<typename T1, typename T2>
 static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2>& t) {
-  EncodeUnsignedLeb128(out, std::get<0>(t));
-  EncodeUnsignedLeb128(out, std::get<1>(t));
+  EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+  EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
 }
 
 template<typename T1, typename T2>
 static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2>* t) {
-  T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
-  T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+  T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+  T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
   *t = std::make_tuple(v1, v2);
 }
 
 template<typename T1, typename T2, typename T3>
 static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2, T3>& t) {
-  EncodeUnsignedLeb128(out, std::get<0>(t));
-  EncodeUnsignedLeb128(out, std::get<1>(t));
-  EncodeUnsignedLeb128(out, std::get<2>(t));
+  EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+  EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
+  EncodeUnsignedLeb128(out, Encode(std::get<2>(t)));
 }
 
 template<typename T1, typename T2, typename T3>
 static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2, T3>* t) {
-  T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
-  T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
-  T3 v3 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+  T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+  T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
+  T3 v3 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
   *t = std::make_tuple(v1, v2, v3);
 }
 
@@ -381,11 +471,12 @@
   }
 }
 
+template <typename T>
 static inline void EncodeUint16Vector(std::vector<uint8_t>* out,
-                                      const std::vector<uint16_t>& vector) {
+                                      const std::vector<T>& vector) {
   EncodeUnsignedLeb128(out, vector.size());
-  for (uint16_t entry : vector) {
-    EncodeUnsignedLeb128(out, entry);
+  for (const T& entry : vector) {
+    EncodeUnsignedLeb128(out, Encode(entry));
   }
 }
 
@@ -400,14 +491,16 @@
   }
 }
 
+template<typename T>
 static inline void DecodeUint16Vector(const uint8_t** in,
                                       const uint8_t* end,
-                                      std::vector<uint16_t>* vector) {
+                                      std::vector<T>* vector) {
   DCHECK(vector->empty());
   size_t num_entries = DecodeUint32WithOverflowCheck(in, end);
   vector->reserve(num_entries);
   for (size_t i = 0; i < num_entries; ++i) {
-    vector->push_back(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end)));
+    vector->push_back(
+        Decode<T>(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end))));
   }
 }
 
@@ -436,6 +529,8 @@
   }
 }
 
+}  // namespace
+
 void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
                           std::vector<uint8_t>* buffer) const {
   MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
@@ -599,7 +694,7 @@
       }
     }
 
-    for (uint16_t type_index : dep.second->unverified_classes_) {
+    for (dex::TypeIndex type_index : dep.second->unverified_classes_) {
       vios->Stream()
           << dex_file.StringByTypeIdx(type_index)
           << " is expected to be verified at runtime\n";
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 7b419d4..e35af41 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -57,14 +57,14 @@
 
   // Record the verification status of the class at `type_idx`.
   static void MaybeRecordVerificationStatus(const DexFile& dex_file,
-                                            uint16_t type_idx,
+                                            dex::TypeIndex type_idx,
                                             MethodVerifier::FailureKind failure_kind)
       REQUIRES(!Locks::verifier_deps_lock_);
 
   // Record the outcome `klass` of resolving type `type_idx` from `dex_file`.
   // If `klass` is null, the class is assumed unresolved.
   static void MaybeRecordClassResolution(const DexFile& dex_file,
-                                         uint16_t type_idx,
+                                         dex::TypeIndex type_idx,
                                          mirror::Class* klass)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::verifier_deps_lock_);
@@ -116,7 +116,7 @@
 
   // NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are
   // fully created.
-  const std::vector<uint16_t>& GetUnverifiedClasses(const DexFile& dex_file) const
+  const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const
       NO_THREAD_SAFETY_ANALYSIS {
     return GetDexFileDeps(dex_file)->unverified_classes_;
   }
@@ -124,15 +124,15 @@
  private:
   static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1);
 
-  using ClassResolutionBase = std::tuple<uint32_t, uint16_t>;
+  using ClassResolutionBase = std::tuple<dex::TypeIndex, uint16_t>;
   struct ClassResolution : public ClassResolutionBase {
     ClassResolution() = default;
     ClassResolution(const ClassResolution&) = default;
-    ClassResolution(uint32_t type_idx, uint16_t access_flags)
+    ClassResolution(dex::TypeIndex type_idx, uint16_t access_flags)
         : ClassResolutionBase(type_idx, access_flags) {}
 
     bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
-    uint32_t GetDexTypeIndex() const { return std::get<0>(*this); }
+    dex::TypeIndex GetDexTypeIndex() const { return std::get<0>(*this); }
     uint16_t GetAccessFlags() const { return std::get<1>(*this); }
   };
 
@@ -193,7 +193,7 @@
     std::set<MethodResolution> interface_methods_;
 
     // List of classes that were not fully verified in that dex file.
-    std::vector<uint16_t> unverified_classes_;
+    std::vector<dex::TypeIndex> unverified_classes_;
 
     bool Equals(const DexFileDeps& rhs) const;
   };
@@ -232,13 +232,24 @@
 
   // Returns a string ID of the descriptor of the declaring class of `element`,
   // or `kUnresolvedMarker` if `element` is null.
-  template <typename T>
-  uint32_t GetDeclaringClassStringId(const DexFile& dex_file, T* element)
+  uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
+                                           uint32_t dex_method_idx,
+                                           ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(Locks::verifier_deps_lock_);
+  uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
+                                          uint32_t dex_field_idx,
+                                          ArtField* field)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(Locks::verifier_deps_lock_);
+
+  // Returns a string ID of the descriptor of the class.
+  uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(Locks::verifier_deps_lock_);
 
   void AddClassResolution(const DexFile& dex_file,
-                          uint16_t type_idx,
+                          dex::TypeIndex type_idx,
                           mirror::Class* klass)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::verifier_deps_lock_);
diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc
new file mode 100644
index 0000000..ff33709
--- /dev/null
+++ b/test/626-const-class-linking/clear_dex_cache_types.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "jni.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+namespace {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_clearResolvedTypes(JNIEnv*, jclass, jclass cls) {
+  ScopedObjectAccess soa(Thread::Current());
+  mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
+  for (size_t i = 0, num_types = dex_cache->NumResolvedTypes(); i != num_types; ++i) {
+    dex_cache->SetResolvedType(dex::TypeIndex(i), ObjPtr<mirror::Class>(nullptr));
+  }
+}
+
+}  // namespace
+
+}  // namespace art
diff --git a/test/626-const-class-linking/expected.txt b/test/626-const-class-linking/expected.txt
new file mode 100644
index 0000000..e83aa78
--- /dev/null
+++ b/test/626-const-class-linking/expected.txt
@@ -0,0 +1,62 @@
+JNI_OnLoad called
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+testClearDexCache done
+first: Helper1 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+first: Helper2 class loader: DelegatingLoader
+second: Test class loader: DefiningLoader
+testMultiDex done
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+total: 4
+  throwables: 0
+  class_weaks: 4 (1 unique)
+testRacyLoader done
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyLoader
+second: Test class loader: DefiningLoader
+first: Helper3 class loader: RacyLoader
+second: Test3 class loader: DefiningLoader
+first: Helper3 class loader: RacyLoader
+second: Test3 class loader: DefiningLoader
+total: 4
+  throwables: 0
+  class_weaks: 4 (2 unique)
+testRacyLoader2 done
+MisbehavingLoader loading Helper2 instead of Test
+java.lang.NoClassDefFoundError: Initiating class loader of type MisbehavingLoader returned class Helper2 instead of Test.
+testMisbehavingLoader done
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+total: 4
+  throwables: 0
+  class_weaks: 4 (1 unique)
+testRacyMisbehavingLoader done
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+first: Helper1 class loader: RacyMisbehavingLoader
+second: Test class loader: DefiningLoader
+total: 4
+  throwables: 0
+  class_weaks: 4 (1 unique)
+testRacyMisbehavingLoader2 done
diff --git a/test/626-const-class-linking/info.txt b/test/626-const-class-linking/info.txt
new file mode 100644
index 0000000..9c19a46
--- /dev/null
+++ b/test/626-const-class-linking/info.txt
@@ -0,0 +1,3 @@
+Test that once a const-class instruction is linked, it will keep referring
+to the same class even in the presence of custom class loaders even after
+clearing the dex cache type array.
diff --git a/test/626-const-class-linking/multidex.jpp b/test/626-const-class-linking/multidex.jpp
new file mode 100644
index 0000000..c7a6648
--- /dev/null
+++ b/test/626-const-class-linking/multidex.jpp
@@ -0,0 +1,27 @@
+ClassPair:
+  @@com.android.jack.annotations.ForceInMainDex
+  class ClassPair
+DefiningLoader:
+  @@com.android.jack.annotations.ForceInMainDex
+  class DefiningLoader
+DelegatingLoader:
+  @@com.android.jack.annotations.ForceInMainDex
+  class DelegatingLoader
+Helper1:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Helper1
+Main:
+  @@com.android.jack.annotations.ForceInMainDex
+  class Main
+MisbehavingLoader:
+  @@com.android.jack.annotations.ForceInMainDex
+  class MisbehavingLoader
+RacyLoader:
+  @@com.android.jack.annotations.ForceInMainDex
+  class RacyLoader
+RacyMisbehavingHelper:
+  @@com.android.jack.annotations.ForceInMainDex
+  class RacyMisbehavingHelper
+RacyMisbehavingLoader:
+  @@com.android.jack.annotations.ForceInMainDex
+  class RacyMisbehavingLoader
diff --git a/test/626-const-class-linking/src-multidex/Helper2.java b/test/626-const-class-linking/src-multidex/Helper2.java
new file mode 100644
index 0000000..5bb31ee
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Helper2.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Helper2 {
+    public static ClassPair get() {
+        Class<?> helper2_class = Helper2.class;
+        Class<?> test_class = Test.class;
+        return new ClassPair(helper2_class, test_class);
+    }
+}
diff --git a/test/626-const-class-linking/src-multidex/Helper3.java b/test/626-const-class-linking/src-multidex/Helper3.java
new file mode 100644
index 0000000..af996de
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Helper3.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Helper3 {
+    public static ClassPair get() {
+        Class<?> helper3_class = Helper3.class;
+        Class<?> test3_class = Test3.class;
+        return new ClassPair(helper3_class, test3_class);
+    }
+}
diff --git a/test/626-const-class-linking/src-multidex/Test.java b/test/626-const-class-linking/src-multidex/Test.java
new file mode 100644
index 0000000..1b0cc2a
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Test.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Test {
+}
diff --git a/test/626-const-class-linking/src-multidex/Test3.java b/test/626-const-class-linking/src-multidex/Test3.java
new file mode 100644
index 0000000..c4b134d
--- /dev/null
+++ b/test/626-const-class-linking/src-multidex/Test3.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Test3 {
+}
diff --git a/test/626-const-class-linking/src/ClassPair.java b/test/626-const-class-linking/src/ClassPair.java
new file mode 100644
index 0000000..b07036c
--- /dev/null
+++ b/test/626-const-class-linking/src/ClassPair.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class ClassPair {
+    public Class<?> first;
+    public Class<?> second;
+
+    public ClassPair(Class<?> first, Class<?> second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    public void print() {
+        String first_loader_name = first.getClassLoader().getClass().getName();
+        System.out.println("first: " + first.getName() + " class loader: " + first_loader_name);
+        String second_loader_name = second.getClassLoader().getClass().getName();
+        System.out.println("second: " + second.getName() + " class loader: " + second_loader_name);
+    }
+}
diff --git a/test/626-const-class-linking/src/DefiningLoader.java b/test/626-const-class-linking/src/DefiningLoader.java
new file mode 100644
index 0000000..b17ab77
--- /dev/null
+++ b/test/626-const-class-linking/src/DefiningLoader.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * A class loader with atypical behavior: we try to load a private
+ * class implementation before asking the system or boot loader.  This
+ * is used to create multiple classes with identical names in a single VM.
+ *
+ * If DexFile is available, we use that; if not, we assume we're not in
+ * Dalvik and instantiate the class with defineClass().
+ *
+ * The location of the DEX files and class data is dependent upon the
+ * test framework.
+ */
+public class DefiningLoader extends ClassLoader {
+    static {
+        // For JVM, register as parallel capable.
+        // Android treats all class loaders as parallel capable and makes this a no-op.
+        registerAsParallelCapable();
+    }
+
+    /* this is where the .class files live */
+    static final String CLASS_PATH1 = "classes/";
+    static final String CLASS_PATH2 = "classes2/";
+
+    /* this is the DEX/Jar file */
+    static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/626-const-class-linking.jar";
+
+    /* on Dalvik, this is a DexFile; otherwise, it's null */
+    private Class<?> mDexClass;
+
+    private Object mDexFile;
+
+    /**
+     * Construct DefiningLoader, grabbing a reference to the DexFile class
+     * if we're running under Dalvik.
+     */
+    public DefiningLoader(ClassLoader parent) {
+        super(parent);
+
+        try {
+            mDexClass = parent.loadClass("dalvik.system.DexFile");
+        } catch (ClassNotFoundException cnfe) {
+            // ignore -- not running Dalvik
+        }
+    }
+
+    /**
+     * Finds the class with the specified binary name.
+     *
+     * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
+     * If we don't find a match, we throw an exception.
+     */
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (mDexClass != null) {
+            return findClassDalvik(name);
+        } else {
+            return findClassNonDalvik(name);
+        }
+    }
+
+    /**
+     * Finds the class with the specified binary name, from a DEX file.
+     */
+    private Class<?> findClassDalvik(String name)
+        throws ClassNotFoundException {
+
+        if (mDexFile == null) {
+            synchronized (DefiningLoader.class) {
+                Constructor<?> ctor;
+                /*
+                 * Construct a DexFile object through reflection.
+                 */
+                try {
+                    ctor = mDexClass.getConstructor(String.class);
+                } catch (NoSuchMethodException nsme) {
+                    throw new ClassNotFoundException("getConstructor failed",
+                        nsme);
+                }
+
+                try {
+                    mDexFile = ctor.newInstance(DEX_FILE);
+                } catch (InstantiationException ie) {
+                    throw new ClassNotFoundException("newInstance failed", ie);
+                } catch (IllegalAccessException iae) {
+                    throw new ClassNotFoundException("newInstance failed", iae);
+                } catch (InvocationTargetException ite) {
+                    throw new ClassNotFoundException("newInstance failed", ite);
+                }
+            }
+        }
+
+        /*
+         * Call DexFile.loadClass(String, ClassLoader).
+         */
+        Method meth;
+
+        try {
+            meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
+        } catch (NoSuchMethodException nsme) {
+            throw new ClassNotFoundException("getMethod failed", nsme);
+        }
+
+        try {
+            meth.invoke(mDexFile, name, this);
+        } catch (IllegalAccessException iae) {
+            throw new ClassNotFoundException("loadClass failed", iae);
+        } catch (InvocationTargetException ite) {
+            throw new ClassNotFoundException("loadClass failed",
+                ite.getCause());
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds the class with the specified binary name, from .class files.
+     */
+    private Class<?> findClassNonDalvik(String name)
+        throws ClassNotFoundException {
+
+        String[] pathNames = { CLASS_PATH1 + name + ".class", CLASS_PATH2 + name + ".class" };
+
+        String pathName = null;
+        RandomAccessFile raf = null;
+
+        for (String pn : pathNames) {
+            pathName = pn;
+            try {
+                //System.out.println("--- Defining: looking for " + pathName);
+                raf = new RandomAccessFile(new File(pathName), "r");
+                break;
+            } catch (FileNotFoundException fnfe) {
+            }
+        }
+        if (raf == null) {
+            throw new ClassNotFoundException("Not found: " + pathNames[0] + ":" + pathNames[1]);
+        }
+
+        /* read the entire file in */
+        byte[] fileData;
+        try {
+            fileData = new byte[(int) raf.length()];
+            raf.readFully(fileData);
+        } catch (IOException ioe) {
+            throw new ClassNotFoundException("Read error: " + pathName);
+        } finally {
+            try {
+                raf.close();
+            } catch (IOException ioe) {
+                // drop
+            }
+        }
+
+        /* create the class */
+        //System.out.println("--- Defining: defining " + name);
+        try {
+            return defineClass(name, fileData, 0, fileData.length);
+        } catch (Throwable th) {
+            throw new ClassNotFoundException("defineClass failed", th);
+        }
+    }
+
+    /**
+     * Load a class.
+     *
+     * Normally a class loader wouldn't override this, but we want our
+     * version of the class to take precedence over an already-loaded
+     * version.
+     *
+     * We still want the system classes (e.g. java.lang.Object) from the
+     * bootstrap class loader.
+     */
+    synchronized protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        Class<?> res;
+
+        /*
+         * 1. Invoke findLoadedClass(String) to check if the class has
+         * already been loaded.
+         *
+         * This doesn't change.
+         */
+        res = findLoadedClass(name);
+        if (res != null) {
+            // System.out.println("FancyLoader.loadClass: " + name + " already loaded");
+            if (resolve)
+                resolveClass(res);
+            return res;
+        }
+
+        /*
+         * 3. Invoke the findClass(String) method to find the class.
+         */
+        try {
+            res = findClass(name);
+            if (resolve)
+                resolveClass(res);
+        }
+        catch (ClassNotFoundException e) {
+            // we couldn't find it, so eat the exception and keep going
+        }
+
+        /*
+         * 2. Invoke the loadClass method on the parent class loader.  If
+         * the parent loader is null the class loader built-in to the
+         * virtual machine is used, instead.
+         *
+         * (Since we're not in java.lang, we can't actually invoke the
+         * parent's loadClass() method, but we passed our parent to the
+         * super-class which can take care of it for us.)
+         */
+        res = super.loadClass(name, resolve);   // returns class or throws
+        return res;
+    }
+}
diff --git a/test/626-const-class-linking/src/DelegatingLoader.java b/test/626-const-class-linking/src/DelegatingLoader.java
new file mode 100644
index 0000000..49955d4
--- /dev/null
+++ b/test/626-const-class-linking/src/DelegatingLoader.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class DelegatingLoader extends DefiningLoader {
+    private DefiningLoader defining_loader;
+
+    public DelegatingLoader(ClassLoader parent, DefiningLoader defining_loader) {
+        super(parent);
+        this.defining_loader = defining_loader;
+    }
+
+    public void resetDefiningLoader(DefiningLoader defining_loader) {
+        this.defining_loader = defining_loader;
+    }
+
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (name.equals("Test")) {
+            throw new Error("Unexpected DelegatingLoader.findClass(\"Test\")");
+        }
+        return super.findClass(name);
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        if (name.equals("Test")) {
+            return defining_loader.loadClass(name, resolve);
+        }
+        return super.loadClass(name, resolve);
+    }
+}
diff --git a/test/626-const-class-linking/src/Helper1.java b/test/626-const-class-linking/src/Helper1.java
new file mode 100644
index 0000000..ff9cd1a
--- /dev/null
+++ b/test/626-const-class-linking/src/Helper1.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Helper1 {
+    public static ClassPair get() {
+        Class<?> helper1_class = Helper1.class;
+        Class<?> test_class = Test.class;
+        return new ClassPair(helper1_class, test_class);
+    }
+}
diff --git a/test/626-const-class-linking/src/Main.java b/test/626-const-class-linking/src/Main.java
new file mode 100644
index 0000000..44ea1c1
--- /dev/null
+++ b/test/626-const-class-linking/src/Main.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class Main {
+    public static void main(String[] args) throws Exception {
+        try {
+            System.loadLibrary(args[0]);
+        } catch (UnsatisfiedLinkError ule) {
+            usingRI = true;
+            // Add expected JNI_OnLoad log line to match expected.txt.
+            System.out.println("JNI_OnLoad called");
+        }
+
+        testClearDexCache();
+        testMultiDex();
+        testRacyLoader();
+        testRacyLoader2();
+        testMisbehavingLoader();
+        testRacyMisbehavingLoader();
+        testRacyMisbehavingLoader2();
+    }
+
+    private static void testClearDexCache() throws Exception {
+        DelegatingLoader delegating_loader = createDelegatingLoader();
+        Class<?> helper = delegating_loader.loadClass("Helper1");
+
+        WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper);
+        changeInner(delegating_loader);
+        if (!usingRI) {
+            clearResolvedTypes(helper);
+        }
+        Runtime.getRuntime().gc();
+        WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper);
+
+        Class<?> test1 = weak_test1.get();
+        if (test1 == null) {
+            System.out.println("test1 disappeared");
+        }
+        Class<?> test2 = weak_test2.get();
+        if (test2 == null) {
+            System.out.println("test2 disappeared");
+        }
+        if (test1 != test2) {
+            System.out.println("test1 != test2");
+        }
+
+        test1 = null;
+        test2 = null;
+        if (!usingRI) {
+            clearResolvedTypes(helper);
+        }
+        helper = null;
+        delegating_loader = null;
+        Runtime.getRuntime().gc();
+        if (weak_test1.get() != null) {
+            System.out.println("weak_test1 still not null");
+        }
+        if (weak_test2.get() != null) {
+            System.out.println("weak_test2 still not null");
+        }
+        System.out.println("testClearDexCache done");
+    }
+
+    private static void testMultiDex() throws Exception {
+        DelegatingLoader delegating_loader = createDelegatingLoader();
+
+        Class<?> helper1 = delegating_loader.loadClass("Helper1");
+        WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1);
+
+        changeInner(delegating_loader);
+
+        Class<?> helper2 = delegating_loader.loadClass("Helper2");
+        WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2);
+
+        Class<?> test1 = weak_test1.get();
+        if (test1 == null) {
+            System.out.println("test1 disappeared");
+        }
+        Class<?> test2 = weak_test2.get();
+        if (test2 == null) {
+            System.out.println("test2 disappeared");
+        }
+        if (test1 != test2) {
+            System.out.println("test1 != test2");
+        }
+
+        test1 = null;
+        test2 = null;
+        delegating_loader = null;
+        helper1 = null;
+        helper2 = null;
+        Runtime.getRuntime().gc();
+        if (weak_test1.get() != null) {
+            System.out.println("weak_test1 still not null");
+        }
+        if (weak_test2.get() != null) {
+            System.out.println("weak_test2 still not null");
+        }
+        System.out.println("testMultiDex done");
+    }
+
+    private static void testMisbehavingLoader() throws Exception {
+        ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+        DefiningLoader defining_loader = new DefiningLoader(system_loader);
+        MisbehavingLoader misbehaving_loader =
+            new MisbehavingLoader(system_loader, defining_loader);
+        Class<?> helper = misbehaving_loader.loadClass("Helper1");
+
+        try {
+            WeakReference<Class<?>> weak_test = wrapHelperGet(helper);
+        } catch (InvocationTargetException ite) {
+            String message = ite.getCause().getMessage();
+            if (usingRI && "Test".equals(message)) {
+              // Replace RI message with dalvik message to match expected.txt.
+              message = "Initiating class loader of type " +
+                  misbehaving_loader.getClass().getName() +
+                  " returned class Helper2 instead of Test.";
+            }
+            System.out.println(ite.getCause().getClass().getName() + ": " + message);
+        }
+        System.out.println("testMisbehavingLoader done");
+    }
+
+    private static void testRacyLoader() throws Exception {
+        final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+        final Thread[] threads = new Thread[4];
+        final Object[] results = new Object[threads.length];
+
+        final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
+        final Class<?> helper1 = racy_loader.loadClass("Helper1");
+
+        for (int i = 0; i != threads.length; ++i) {
+            final int my_index = i;
+            Thread t = new Thread() {
+                public void run() {
+                    try {
+                        Method get = helper1.getDeclaredMethod("get");
+                        results[my_index] = get.invoke(null);
+                    } catch (InvocationTargetException ite) {
+                        results[my_index] = ite.getCause();
+                    } catch (Throwable t) {
+                        results[my_index] = t;
+                    }
+                }
+            };
+            t.start();
+            threads[i] = t;
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        dumpResultStats(results);
+        System.out.println("testRacyLoader done");
+    }
+
+    private static void testRacyLoader2() throws Exception {
+        final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+        final Thread[] threads = new Thread[4];
+        final Object[] results = new Object[threads.length];
+
+        final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
+        final Class<?> helper1 = racy_loader.loadClass("Helper1");
+        final Class<?> helper3 = racy_loader.loadClass("Helper3");
+
+        for (int i = 0; i != threads.length; ++i) {
+            final int my_index = i;
+            Thread t = new Thread() {
+                public void run() {
+                    try {
+                        Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3;
+                        Method get = helper.getDeclaredMethod("get");
+                        results[my_index] = get.invoke(null);
+                    } catch (InvocationTargetException ite) {
+                        results[my_index] = ite.getCause();
+                    } catch (Throwable t) {
+                        results[my_index] = t;
+                    }
+                }
+            };
+            t.start();
+            threads[i] = t;
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        dumpResultStats(results);
+        System.out.println("testRacyLoader2 done");
+    }
+
+    private static void dumpResultStats(Object[] results) throws Exception {
+        int throwables = 0;
+        int class_weaks = 0;
+        int unique_class_weaks = 0;
+        for (int i = 0; i != results.length; ++i) {
+            Object r = results[i];
+            if (r instanceof Throwable) {
+                ++throwables;
+                System.out.println(((Throwable) r).getMessage());
+            } else if (isClassPair(r)) {
+                printPair(r);
+                Object ref = getSecond(r);
+                ++class_weaks;
+                ++unique_class_weaks;
+                for (int j = 0; j != i; ++j) {
+                    Object rj = results[j];
+                    if (isClassPair(results[j]) && getSecond(results[j]) == ref) {
+                        --unique_class_weaks;
+                        break;
+                    }
+                }
+            }
+        }
+        System.out.println("total: " + results.length);
+        System.out.println("  throwables: " + throwables);
+        System.out.println("  class_weaks: " + class_weaks
+            + " (" + unique_class_weaks + " unique)");
+    }
+
+    private static void testRacyMisbehavingLoader() throws Exception {
+        final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+        final Thread[] threads = new Thread[4];
+        final Object[] results = new Object[threads.length];
+
+        final RacyMisbehavingLoader racy_loader =
+            new RacyMisbehavingLoader(system_loader, threads.length, false);
+        final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
+
+        for (int i = 0; i != threads.length; ++i) {
+            final int my_index = i;
+            Thread t = new Thread() {
+                public void run() {
+                    try {
+                        Method get = helper1.getDeclaredMethod("get");
+                        results[my_index] = get.invoke(null);
+                    } catch (InvocationTargetException ite) {
+                        results[my_index] = ite.getCause();
+                    } catch (Throwable t) {
+                        results[my_index] = t;
+                    }
+                }
+            };
+            t.start();
+            threads[i] = t;
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        dumpResultStats(results);
+        System.out.println("testRacyMisbehavingLoader done");
+    }
+
+    private static void testRacyMisbehavingLoader2() throws Exception {
+      final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+
+      final Thread[] threads = new Thread[4];
+      final Object[] results = new Object[threads.length];
+
+      final RacyMisbehavingLoader racy_loader =
+          new RacyMisbehavingLoader(system_loader, threads.length, true);
+      final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
+
+      for (int i = 0; i != threads.length; ++i) {
+          final int my_index = i;
+          Thread t = new Thread() {
+              public void run() {
+                  try {
+                      Method get = helper1.getDeclaredMethod("get");
+                      results[my_index] = get.invoke(null);
+                  } catch (InvocationTargetException ite) {
+                      results[my_index] = ite.getCause();
+                  } catch (Throwable t) {
+                      results[my_index] = t;
+                  }
+              }
+          };
+          t.start();
+          threads[i] = t;
+      }
+      for (Thread t : threads) {
+          t.join();
+      }
+      dumpResultStats(results);
+      System.out.println("testRacyMisbehavingLoader2 done");
+  }
+
+    private static DelegatingLoader createDelegatingLoader() {
+        ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+        DefiningLoader defining_loader = new DefiningLoader(system_loader);
+        return new DelegatingLoader(system_loader, defining_loader);
+    }
+
+    private static void changeInner(DelegatingLoader delegating_loader) {
+        ClassLoader system_loader = ClassLoader.getSystemClassLoader();
+        DefiningLoader defining_loader = new DefiningLoader(system_loader);
+        delegating_loader.resetDefiningLoader(defining_loader);
+    }
+
+    private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception {
+        Method get = helper.getDeclaredMethod("get");
+        Object pair = get.invoke(null);
+        printPair(pair);
+        return new WeakReference<Class<?>>(getSecond(pair));
+    }
+
+    private static void printPair(Object pair) throws Exception {
+        Method print = pair.getClass().getDeclaredMethod("print");
+        print.invoke(pair);
+    }
+
+    private static Class<?> getSecond(Object pair) throws Exception {
+        Field second = pair.getClass().getDeclaredField("second");
+        return (Class<?>) second.get(pair);
+    }
+
+    private static boolean isClassPair(Object r) {
+        return r != null && r.getClass().getName().equals("ClassPair");
+    }
+
+    public static native void clearResolvedTypes(Class<?> c);
+
+    static boolean usingRI = false;
+}
diff --git a/test/626-const-class-linking/src/MisbehavingLoader.java b/test/626-const-class-linking/src/MisbehavingLoader.java
new file mode 100644
index 0000000..61639ba
--- /dev/null
+++ b/test/626-const-class-linking/src/MisbehavingLoader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Class loader that returns Helper2.class when asked to load "Test".
+public class MisbehavingLoader extends DefiningLoader {
+    private DefiningLoader defining_loader;
+
+    public MisbehavingLoader(ClassLoader parent, DefiningLoader defining_loader) {
+        super(parent);
+        this.defining_loader = defining_loader;
+    }
+
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (name.equals("Helper1") || name.equals("Helper2")) {
+            return super.findClass(name);
+        } else if (name.equals("Test")) {
+            throw new Error("Unexpected MisbehavingLoader.findClass(\"Test\")");
+        }
+        return super.findClass(name);
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        if (name.equals("Helper1") || name.equals("Helper2")) {
+            return super.loadClass(name, resolve);
+        } else if (name.equals("Test")) {
+            // Ask for a different class.
+            System.out.println("MisbehavingLoader loading Helper2 instead of Test");
+            return defining_loader.loadClass("Helper2", resolve);
+        }
+        return super.loadClass(name, resolve);
+    }
+}
diff --git a/test/626-const-class-linking/src/RacyLoader.java b/test/626-const-class-linking/src/RacyLoader.java
new file mode 100644
index 0000000..abfc8ed
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyLoader.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class RacyLoader extends DefiningLoader {
+    static {
+        // For JVM, register as parallel capable.
+        // Android treats all class loaders as parallel capable and makes this a no-op.
+        registerAsParallelCapable();
+    }
+
+    private Object lock = new Object();
+    private int index = 0;
+    private int count;
+
+    private DefiningLoader[] defining_loaders;
+
+    public RacyLoader(ClassLoader parent, int count) {
+        super(parent);
+        this.count = count;
+        defining_loaders = new DefiningLoader[2];
+        for (int i = 0; i != defining_loaders.length; ++i) {
+            defining_loaders[i] = new DefiningLoader(parent);
+        }
+    }
+
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (name.equals("Test") || name.equals("Test3")) {
+            throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
+        }
+        return super.findClass(name);
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        if (name.equals("Test") || name.equals("Test3")) {
+            int my_index = syncWithOtherInstances(count);
+            Class<?> result = defining_loaders[my_index & 1].loadClass(name, resolve);
+            syncWithOtherInstances(2 * count);
+            return result;
+        }
+        return super.loadClass(name, resolve);
+    }
+
+    private int syncWithOtherInstances(int limit) {
+        int my_index;
+        synchronized (lock) {
+            my_index = index;
+            ++index;
+            if (index != limit) {
+                try {
+                    lock.wait(2000);
+                    if (index < limit) {
+                        throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
+                    }
+                } catch (InterruptedException ie) {
+                    throw new Error(ie);
+                }
+            } else {
+                lock.notifyAll();
+            }
+        }
+        return my_index;
+    }
+}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingHelper.java b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
new file mode 100644
index 0000000..4525278
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyMisbehavingHelper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class RacyMisbehavingHelper {
+    public static ClassPair get() {
+        Class<?> helper1_class = Helper1.class;
+        Class<?> test_class = Test.class;
+        try {
+            // After loading the correct class, allow loading the incorrect class.
+            ClassLoader loader = helper1_class.getClassLoader();
+            Method reportAfterLoading = loader.getClass().getDeclaredMethod("reportAfterLoading");
+            reportAfterLoading.invoke(loader);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        return new ClassPair(helper1_class, test_class);
+    }
+}
diff --git a/test/626-const-class-linking/src/RacyMisbehavingLoader.java b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
new file mode 100644
index 0000000..d09888e
--- /dev/null
+++ b/test/626-const-class-linking/src/RacyMisbehavingLoader.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class RacyMisbehavingLoader extends DefiningLoader {
+    static {
+        // For JVM, register as parallel capable.
+        // Android treats all class loaders as parallel capable and makes this a no-op.
+        registerAsParallelCapable();
+    }
+
+    private Object lock = new Object();
+    private int index = 0;
+    private int count;
+    private boolean throw_error;
+
+    private DefiningLoader[] defining_loaders;
+
+    public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
+        super(parent);
+        this.count = count;
+        this.throw_error = throw_error;
+        defining_loaders = new DefiningLoader[2];
+        for (int i = 0; i != defining_loaders.length; ++i) {
+            defining_loaders[i] = new DefiningLoader(parent);
+        }
+    }
+
+    public void reportAfterLoading() {
+        synchronized (lock) {
+            ++index;
+            if (index == 2 * count) {
+                lock.notifyAll();
+            }
+        }
+    }
+
+    protected Class<?> findClass(String name) throws ClassNotFoundException
+    {
+        if (name.equals("Test")) {
+            throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
+        }
+        return super.findClass(name);
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        if (name.equals("Test")) {
+            int my_index = syncWithOtherInstances(count);
+            Class<?> result;
+            if ((my_index & 1) == 0) {
+              // Do not delay loading the correct class.
+              result = defining_loaders[my_index & 1].loadClass(name, resolve);
+            } else {
+              // Delay loading the wrong class.
+              syncWithOtherInstances(2 * count);
+              if (throw_error) {
+                throw new Error("RacyMisbehavingLoader throw_error=true");
+              }
+              result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
+            }
+            return result;
+        }
+        return super.loadClass(name, resolve);
+    }
+
+    private int syncWithOtherInstances(int limit) {
+        int my_index;
+        synchronized (lock) {
+            my_index = index;
+            ++index;
+            if (index != limit) {
+                try {
+                    lock.wait(2000);
+                    if (index < limit) {
+                        throw new Error("Timed out; my_index=" + my_index + ", index=" + index);
+                    }
+                } catch (InterruptedException ie) {
+                    throw new Error(ie);
+                }
+            } else {
+                lock.notifyAll();
+            }
+        }
+        return my_index;
+    }
+}
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index 8f0850b..3ed91d7 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -66,6 +66,15 @@
     jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
   }
 
+  // Also run GetMethodName with all parameter pointers null to check for segfaults.
+  jvmtiError result2 = jvmti_env->GetMethodName(id, nullptr, nullptr, nullptr);
+  if (result2 != JVMTI_ERROR_NONE) {
+    char* err;
+    jvmti_env->GetErrorName(result2, &err);
+    printf("Failure running GetMethodName(null, null, null): %s\n", err);
+    return nullptr;
+  }
+
   return ret;
 }
 
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index d1ddbae..8002cfa 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -45,7 +45,7 @@
 6@1000 --(class)--> 1000@0 [size=123, length=-1]
 ---
 root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local)--> 1@1000 [size=16, length=-1]
 root@root --(thread)--> 1@1000 [size=16, length=-1]
 root@root --(thread)--> 3000@0 [size=132, length=-1]
@@ -67,7 +67,7 @@
 6@1000 --(class)--> 1000@0 [size=123, length=-1]
 ---
 root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local)--> 1@1000 [size=16, length=-1]
 root@root --(stack-local)--> 2@1000 [size=16, length=-1]
 root@root --(thread)--> 1@1000 [size=16, length=-1]
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 871902e..340671d 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -234,6 +234,41 @@
       jint length_;
     };
 
+    class JNILocalElement : public Elem {
+     public:
+      JNILocalElement(const std::string& referrer,
+                      const std::string& referree,
+                      jlong size,
+                      jint length,
+                      const jvmtiHeapReferenceInfo* reference_info)
+          : Elem(referrer, referree, size, length) {
+        memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
+      }
+
+     protected:
+      std::string PrintArrowType() const OVERRIDE {
+        char* name = nullptr;
+        if (info_.jni_local.method != nullptr) {
+          jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
+        }
+        std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
+                                       "method=%s]",
+                                       info_.jni_local.thread_id,
+                                       info_.jni_local.thread_tag,
+                                       info_.jni_local.depth,
+                                       name == nullptr ? "<null>" : name);
+        if (name != nullptr) {
+          jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
+        }
+
+        return ret;
+      }
+
+     private:
+      const std::string string_;
+      jvmtiHeapReferenceInfo info_;
+    };
+
     // For simple or unimplemented cases.
     class StringElement : public Elem {
      public:
@@ -351,11 +386,11 @@
                                                          length,
                                                          "stack-local"));
         case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
-          return std::unique_ptr<Elem>(new StringElement(referrer,
-                                                         referree,
-                                                         size,
-                                                         length,
-                                                         "jni-local"));
+          return std::unique_ptr<Elem>(new JNILocalElement(referrer,
+                                                           referree,
+                                                           size,
+                                                           length,
+                                                           reference_info));
         case JVMTI_HEAP_REFERENCE_THREAD:
           return std::unique_ptr<Elem>(new StringElement(referrer,
                                                          referree,
diff --git a/test/Android.bp b/test/Android.bp
index fe20f29..39a4059 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -314,6 +314,7 @@
         "595-profile-saving/profile-saving.cc",
         "596-app-images/app_images.cc",
         "597-deopt-new-string/deopt.cc",
+        "626-const-class-linking/clear_dex_cache_types.cc",
     ],
     shared_libs: [
         "libbacktrace",
diff --git a/test/etc/default-build b/test/etc/default-build
index e663496..408dcfd 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -273,8 +273,10 @@
 fi
 
 # Create a single jar with two dex files for multidex.
-if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
-  zip $TEST_NAME.jar classes.dex classes2.dex
-elif [ ${NEED_DEX} = "true" ]; then
-  zip $TEST_NAME.jar classes.dex
+if [ ${NEED_DEX} = "true" ]; then
+  if [ ${HAS_SRC_MULTIDEX} = "true" ] || [ ${HAS_SMALI_MULTIDEX} = "true" ]; then
+    zip $TEST_NAME.jar classes.dex classes2.dex
+  else
+    zip $TEST_NAME.jar classes.dex
+  fi
 fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 06e4219..368c663 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -312,7 +312,8 @@
 if [ "$USE_JVM" = "y" ]; then
   export LD_LIBRARY_PATH=${ANDROID_HOST_OUT}/lib64
   # Xmx is necessary since we don't pass down the ART flags to JVM.
-  cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes ${FLAGS} $MAIN $@ ${ARGS}"
+  # We pass the classes2 path whether it's used (src-multidex) or not.
+  cmdline="${JAVA} ${DEBUGGER_OPTS} ${JVM_VERIFY_ARG} -Xmx256m -classpath classes:classes2 ${FLAGS} $MAIN $@ ${ARGS}"
   if [ "$DEV_MODE" = "y" ]; then
     echo $cmdline
   fi