Replace GcRoots in the verifier to use VariableSizedHandleScope.

This removes the cruft in creating static instances, and the need to
explicitly visit verifier roots.

Test: test.py
Change-Id: Ia0f0a82cbc66bb57f30610587f080e75d4d32e92
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index dc3f6dc..16efc2e 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -634,10 +634,15 @@
                                        /*out*/ std::string* descriptor,
                                        /*out*/ SlotType* type)
       REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    art::StackHandleScope<2> hs(art::Thread::Current());
+    art::Handle<art::mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
+    art::Handle<art::mirror::ClassLoader> class_loader(hs.NewHandle(method->GetClassLoader()));
     std::unique_ptr<art::verifier::MethodVerifier> verifier(
         art::verifier::MethodVerifier::CalculateVerificationInfo(
             art::Thread::Current(),
             method,
+            dex_cache,
+            class_loader,
             dex_pc));
     if (verifier == nullptr) {
       JVMTI_LOG(WARNING, jvmti_) << "Unable to extract verification information from "
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d4e4c3e..a8f5987 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1077,8 +1077,6 @@
   // initialize the StackOverflowError class (as it might require running the verifier). Instead,
   // ensure that the class will be initialized.
   if (kMemoryToolIsAvailable && !Runtime::Current()->IsAotCompiler()) {
-    verifier::ClassVerifier::Init(this);  // Need to prepare the verifier.
-
     ObjPtr<mirror::Class> soe_klass = FindSystemClass(self, "Ljava/lang/StackOverflowError;");
     if (soe_klass == nullptr || !EnsureInitialized(self, hs.NewHandle(soe_klass), true, true)) {
       // Strange, but don't crash.
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index be1c58d..9b4af66 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -129,8 +129,7 @@
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mutator_lock, held_mutexes, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, held_mutexes, flip_function,
                         sizeof(void*) * kLockLevelCount);
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, flip_function, method_verifier, sizeof(void*));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, method_verifier, thread_local_mark_stack, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, flip_function, thread_local_mark_stack, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_mark_stack, async_exception, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, async_exception, top_reflective_handle_scope,
                         sizeof(void*));
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index eccdf2a..36c8cde 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -526,7 +526,6 @@
   oat_file_manager_ = nullptr;
   Thread::Shutdown();
   QuasiAtomic::Shutdown();
-  verifier::ClassVerifier::Shutdown();
 
   // Destroy allocators before shutting down the MemMap because they may use it.
   java_vm_.reset();
@@ -1910,8 +1909,6 @@
 
   CHECK(class_linker_ != nullptr);
 
-  verifier::ClassVerifier::Init(class_linker_);
-
   if (runtime_options.Exists(Opt::MethodTrace)) {
     trace_config_.reset(new TraceConfig());
     trace_config_->trace_file = runtime_options.ReleaseOrDefault(Opt::MethodTraceFile);
@@ -2537,7 +2534,6 @@
       .VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   pre_allocated_NoClassDefFoundError_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal));
   VisitImageRoots(visitor);
-  verifier::ClassVerifier::VisitStaticRoots(visitor);
   VisitTransactionRoots(visitor);
 }
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 00a1468..1b72275 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -109,7 +109,6 @@
 #include "thread-inl.h"
 #include "thread_list.h"
 #include "trace.h"
-#include "verifier/method_verifier.h"
 #include "verify_object.h"
 #include "well_known_classes-inl.h"
 
@@ -4433,9 +4432,6 @@
       mapper.VisitShadowFrame(record->GetShadowFrame());
     }
   }
-  for (auto* verifier = tlsPtr_.method_verifier; verifier != nullptr; verifier = verifier->link_) {
-    verifier->VisitRoots(visitor, RootInfo(kRootNativeStack, thread_id));
-  }
   // Visit roots on this thread's stack
   RuntimeContextType context;
   RootCallbackVisitor visitor_to_callback(visitor, thread_id);
@@ -4640,16 +4636,6 @@
   return mprotect(pregion, kStackOverflowProtectedSize, PROT_READ|PROT_WRITE) == 0;
 }
 
-void Thread::PushVerifier(verifier::MethodVerifier* verifier) {
-  verifier->link_ = tlsPtr_.method_verifier;
-  tlsPtr_.method_verifier = verifier;
-}
-
-void Thread::PopVerifier(verifier::MethodVerifier* verifier) {
-  CHECK_EQ(tlsPtr_.method_verifier, verifier);
-  tlsPtr_.method_verifier = verifier->link_;
-}
-
 size_t Thread::NumberOfHeldMutexes() const {
   size_t count = 0;
   for (BaseMutex* mu : tlsPtr_.held_mutexes) {
diff --git a/runtime/thread.h b/runtime/thread.h
index 8167e70..578f989 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -82,7 +82,6 @@
 }  // namespace mirror
 
 namespace verifier {
-class MethodVerifier;
 class VerifierDeps;
 }  // namespace verifier
 
@@ -1389,9 +1388,6 @@
     return false;
   }
 
-  void PushVerifier(verifier::MethodVerifier* verifier);
-  void PopVerifier(verifier::MethodVerifier* verifier);
-
   void InitStringEntryPoints();
 
   void ModifyDebugDisallowReadBarrier(int8_t delta) {
@@ -1961,7 +1957,6 @@
                                thread_local_alloc_stack_end(nullptr),
                                mutator_lock(nullptr),
                                flip_function(nullptr),
-                               method_verifier(nullptr),
                                thread_local_mark_stack(nullptr),
                                async_exception(nullptr),
                                top_reflective_handle_scope(nullptr),
@@ -2110,9 +2105,6 @@
     // The function used for thread flip.
     Closure* flip_function;
 
-    // Current method verifier, used for root marking.
-    verifier::MethodVerifier* method_verifier;
-
     union {
       // Thread-local mark stack for the concurrent copying collector.
       gc::accounting::AtomicStack<mirror::Object>* thread_local_mark_stack;
diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc
index 8946bb2..40584f4 100644
--- a/runtime/verifier/class_verifier.cc
+++ b/runtime/verifier/class_verifier.cc
@@ -187,17 +187,5 @@
   return failure_data.kind;
 }
 
-void ClassVerifier::Init(ClassLinker* class_linker) {
-  MethodVerifier::Init(class_linker);
-}
-
-void ClassVerifier::Shutdown() {
-  MethodVerifier::Shutdown();
-}
-
-void ClassVerifier::VisitStaticRoots(RootVisitor* visitor) {
-  MethodVerifier::VisitStaticRoots(visitor);
-}
-
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h
index 3048e6f..65bc28c 100644
--- a/runtime/verifier/class_verifier.h
+++ b/runtime/verifier/class_verifier.h
@@ -34,7 +34,6 @@
 class ClassLinker;
 class CompilerCallbacks;
 class DexFile;
-class RootVisitor;
 class Thread;
 
 namespace dex {
@@ -69,12 +68,6 @@
                                  std::string* error)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static void Init(ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_);
-  static void Shutdown();
-
-  static void VisitStaticRoots(RootVisitor* visitor)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
  private:
   DISALLOW_COPY_AND_ASSIGN(ClassVerifier);
 };
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9cdbce9..89e2f04 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4950,9 +4950,10 @@
                                bool allow_thread_suspension,
                                bool aot_mode)
     : self_(self),
+      handles_(self),
       arena_stack_(arena_pool),
       allocator_(&arena_stack_),
-      reg_types_(class_linker, can_load_classes, allocator_, allow_thread_suspension),
+      reg_types_(class_linker, can_load_classes, allocator_, handles_, allow_thread_suspension),
       reg_table_(allocator_),
       work_insn_idx_(dex::kDexNoIndex),
       dex_method_idx_(dex_method_idx),
@@ -4966,11 +4967,9 @@
       class_linker_(class_linker),
       verifier_deps_(verifier_deps),
       link_(nullptr) {
-  self->PushVerifier(this);
 }
 
 MethodVerifier::~MethodVerifier() {
-  Thread::Current()->PopVerifier(this);
   STLDeleteElements(&failure_messages_);
 }
 
@@ -5168,10 +5167,9 @@
 MethodVerifier* MethodVerifier::CalculateVerificationInfo(
       Thread* self,
       ArtMethod* method,
+      Handle<mirror::DexCache> dex_cache,
+      Handle<mirror::ClassLoader> class_loader,
       uint32_t dex_pc) {
-  StackHandleScope<2> hs(self);
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(method->GetClassLoader()));
   std::unique_ptr<impl::MethodVerifier<false>> verifier(
       new impl::MethodVerifier<false>(self,
                                       Runtime::Current()->GetClassLinker(),
@@ -5307,22 +5305,6 @@
                                          api_level);
 }
 
-void MethodVerifier::Init(ClassLinker* class_linker) {
-  art::verifier::RegTypeCache::Init(class_linker);
-}
-
-void MethodVerifier::Shutdown() {
-  verifier::RegTypeCache::ShutDown();
-}
-
-void MethodVerifier::VisitStaticRoots(RootVisitor* visitor) {
-  RegTypeCache::VisitStaticRoots(visitor);
-}
-
-void MethodVerifier::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
-  reg_types_.VisitRoots(visitor, root_info);
-}
-
 std::ostream& MethodVerifier::Fail(VerifyError error, bool pending_exc) {
   // Mark the error type as encountered.
   encountered_failure_types_ |= static_cast<uint32_t>(error);
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 92cfb45..649a245 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -113,6 +113,8 @@
   // No classes will be loaded.
   static MethodVerifier* CalculateVerificationInfo(Thread* self,
                                                    ArtMethod* method,
+                                                   Handle<mirror::DexCache> dex_cache,
+                                                   Handle<mirror::ClassLoader> class_loader,
                                                    uint32_t dex_pc)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -155,16 +157,8 @@
                                uint32_t api_level)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static void Init(ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_);
-  static void Shutdown();
-
   virtual ~MethodVerifier();
 
-  static void VisitStaticRoots(RootVisitor* visitor)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  void VisitRoots(RootVisitor* visitor, const RootInfo& roots)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   const CodeItemDataAccessor& CodeItem() const {
     return code_item_accessor_;
   }
@@ -291,6 +285,9 @@
   // The thread we're verifying on.
   Thread* const self_;
 
+  // Handles for classes in the `RegTypeCache`.
+  VariableSizedHandleScope handles_;
+
   // Arena allocator.
   ArenaStack arena_stack_;
   ScopedArenaAllocator allocator_;
diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h
index efe03a8..7fb24b2 100644
--- a/runtime/verifier/reg_type-inl.h
+++ b/runtime/verifier/reg_type-inl.h
@@ -154,72 +154,6 @@
   return AssignableFrom(*this, src, true, verifier);
 }
 
-inline const DoubleHiType* DoubleHiType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const DoubleLoType* DoubleLoType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const LongHiType* LongHiType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const LongLoType* LongLoType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const FloatType* FloatType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const CharType* CharType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const ShortType* ShortType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const ByteType* ByteType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-
-inline const IntegerType* IntegerType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const BooleanType* BooleanType::GetInstance() {
-  DCHECK(BooleanType::instance_ != nullptr);
-  return BooleanType::instance_;
-}
-
-inline const ConflictType* ConflictType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const UndefinedType* UndefinedType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
-inline const NullType* NullType::GetInstance() {
-  DCHECK(instance_ != nullptr);
-  return instance_;
-}
-
 inline void* RegType::operator new(size_t size, ScopedArenaAllocator* allocator) {
   return allocator->Alloc(size, kArenaAllocMisc);
 }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 40b880e..0433c6d 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -40,21 +40,7 @@
 
 using android::base::StringPrintf;
 
-const UndefinedType* UndefinedType::instance_ = nullptr;
-const ConflictType* ConflictType::instance_ = nullptr;
-const BooleanType* BooleanType::instance_ = nullptr;
-const ByteType* ByteType::instance_ = nullptr;
-const ShortType* ShortType::instance_ = nullptr;
-const CharType* CharType::instance_ = nullptr;
-const FloatType* FloatType::instance_ = nullptr;
-const LongLoType* LongLoType::instance_ = nullptr;
-const LongHiType* LongHiType::instance_ = nullptr;
-const DoubleLoType* DoubleLoType::instance_ = nullptr;
-const DoubleHiType* DoubleHiType::instance_ = nullptr;
-const IntegerType* IntegerType::instance_ = nullptr;
-const NullType* NullType::instance_ = nullptr;
-
-PrimitiveType::PrimitiveType(ObjPtr<mirror::Class> klass,
+PrimitiveType::PrimitiveType(Handle<mirror::Class> klass,
                              const std::string_view& descriptor,
                              uint16_t cache_id)
     : RegType(klass, descriptor, cache_id) {
@@ -62,13 +48,13 @@
   CHECK(!descriptor.empty());
 }
 
-Cat1Type::Cat1Type(ObjPtr<mirror::Class> klass,
+Cat1Type::Cat1Type(Handle<mirror::Class> klass,
                    const std::string_view& descriptor,
                    uint16_t cache_id)
     : PrimitiveType(klass, descriptor, cache_id) {
 }
 
-Cat2Type::Cat2Type(ObjPtr<mirror::Class> klass,
+Cat2Type::Cat2Type(Handle<mirror::Class> klass,
                    const std::string_view& descriptor,
                    uint16_t cache_id)
     : PrimitiveType(klass, descriptor, cache_id) {
@@ -135,191 +121,11 @@
   return "Integer";
 }
 
-const DoubleHiType* DoubleHiType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                                 const std::string_view& descriptor,
-                                                 uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new DoubleHiType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void DoubleHiType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const DoubleLoType* DoubleLoType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                                 const std::string_view& descriptor,
-                                                 uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new DoubleLoType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void DoubleLoType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const LongLoType* LongLoType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                             const std::string_view& descriptor,
-                                             uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new LongLoType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-const LongHiType* LongHiType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                             const std::string_view& descriptor,
-                                             uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new LongHiType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void LongHiType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-void LongLoType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const FloatType* FloatType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                           const std::string_view& descriptor,
-                                           uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new FloatType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void FloatType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const CharType* CharType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                         const std::string_view& descriptor,
-                                         uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new CharType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void CharType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const ShortType* ShortType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                           const std::string_view& descriptor,
-                                           uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new ShortType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void ShortType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const ByteType* ByteType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                         const std::string_view& descriptor,
-                                         uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new ByteType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void ByteType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const IntegerType* IntegerType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                               const std::string_view& descriptor,
-                                               uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new IntegerType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void IntegerType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const ConflictType* ConflictType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                                 const std::string_view& descriptor,
-                                                 uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new ConflictType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void ConflictType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-const BooleanType* BooleanType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                               const std::string_view& descriptor,
-                                               uint16_t cache_id) {
-  CHECK(BooleanType::instance_ == nullptr);
-  instance_ = new BooleanType(klass, descriptor, cache_id);
-  return BooleanType::instance_;
-}
-
-void BooleanType::Destroy() {
-  if (BooleanType::instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
 std::string UndefinedType::Dump() const REQUIRES_SHARED(Locks::mutator_lock_) {
   return "Undefined";
 }
 
-const UndefinedType* UndefinedType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                                   const std::string_view& descriptor,
-                                                   uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new UndefinedType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void UndefinedType::Destroy() {
-  if (instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-PreciseReferenceType::PreciseReferenceType(ObjPtr<mirror::Class> klass,
+PreciseReferenceType::PreciseReferenceType(Handle<mirror::Class> klass,
                                            const std::string_view& descriptor,
                                            uint16_t cache_id)
     : RegType(klass, descriptor, cache_id) {
@@ -935,14 +741,10 @@
   if (!klass_.IsNull()) {
     CHECK(!descriptor_.empty()) << *this;
     std::string temp;
-    CHECK_EQ(descriptor_, klass_.Read()->GetDescriptor(&temp)) << *this;
+    CHECK_EQ(descriptor_, klass_->GetDescriptor(&temp)) << *this;
   }
 }
 
-void RegType::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) const {
-  klass_.VisitRootIfNonNull(visitor, root_info);
-}
-
 void UninitializedThisReferenceType::CheckInvariants() const {
   CHECK_EQ(GetAllocationPc(), 0U) << *this;
 }
@@ -950,19 +752,19 @@
 void UnresolvedUninitializedThisRefType::CheckInvariants() const {
   CHECK_EQ(GetAllocationPc(), 0U) << *this;
   CHECK(!descriptor_.empty()) << *this;
-  CHECK(klass_.IsNull()) << *this;
+  CHECK(!HasClass()) << *this;
 }
 
 void UnresolvedUninitializedRefType::CheckInvariants() const {
   CHECK(!descriptor_.empty()) << *this;
-  CHECK(klass_.IsNull()) << *this;
+  CHECK(!HasClass()) << *this;
 }
 
 UnresolvedMergedType::UnresolvedMergedType(const RegType& resolved,
                                            const BitVector& unresolved,
                                            const RegTypeCache* reg_type_cache,
                                            uint16_t cache_id)
-    : UnresolvedType("", cache_id),
+    : UnresolvedType(reg_type_cache->GetNullHandle(), "", cache_id),
       reg_type_cache_(reg_type_cache),
       resolved_part_(resolved),
       unresolved_types_(unresolved, false, unresolved.GetAllocator()) {
@@ -973,7 +775,7 @@
 
   // Unresolved merged types: merged types should be defined.
   CHECK(descriptor_.empty()) << *this;
-  CHECK(klass_.IsNull()) << *this;
+  CHECK(!HasClass()) << *this;
 
   CHECK(!resolved_part_.IsConflict());
   CHECK(resolved_part_.IsReferenceTypes());
@@ -1017,13 +819,13 @@
 
 void UnresolvedReferenceType::CheckInvariants() const {
   CHECK(!descriptor_.empty()) << *this;
-  CHECK(klass_.IsNull()) << *this;
+  CHECK(!HasClass()) << *this;
 }
 
 void UnresolvedSuperClass::CheckInvariants() const {
   // Unresolved merged types: merged types should be defined.
   CHECK(descriptor_.empty()) << *this;
-  CHECK(klass_.IsNull()) << *this;
+  CHECK(!HasClass()) << *this;
   CHECK_NE(unresolved_child_id_, 0U) << *this;
 }
 
@@ -1032,21 +834,5 @@
   return os;
 }
 
-const NullType* NullType::CreateInstance(ObjPtr<mirror::Class> klass,
-                                         const std::string_view& descriptor,
-                                         uint16_t cache_id) {
-  CHECK(instance_ == nullptr);
-  instance_ = new NullType(klass, descriptor, cache_id);
-  return instance_;
-}
-
-void NullType::Destroy() {
-  if (NullType::instance_ != nullptr) {
-    delete instance_;
-    instance_ = nullptr;
-  }
-}
-
-
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index c13784c..6cc9880 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -29,6 +29,7 @@
 #include "base/macros.h"
 #include "dex/primitive.h"
 #include "gc_root.h"
+#include "handle.h"
 #include "handle_scope.h"
 #include "obj_ptr.h"
 
@@ -193,9 +194,15 @@
   }
   ObjPtr<mirror::Class> GetClass() const REQUIRES_SHARED(Locks::mutator_lock_) {
     DCHECK(!IsUnresolvedReference());
-    DCHECK(!klass_.IsNull()) << Dump();
+    DCHECK(!klass_.IsNull());
     DCHECK(HasClass());
-    return klass_.Read();
+    return klass_.Get();
+  }
+  Handle<mirror::Class> GetClassHandle() const REQUIRES_SHARED(Locks::mutator_lock_) {
+    DCHECK(!IsUnresolvedReference());
+    DCHECK(!klass_.IsNull()) << Dump();
+    DCHECK(HasClass()) << Dump();
+    return klass_;
   }
   uint16_t GetId() const { return cache_id_; }
   const RegType& GetSuperClass(RegTypeCache* cache) const
@@ -247,9 +254,6 @@
 
   virtual ~RegType() {}
 
-  void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   static void* operator new(size_t size) noexcept {
     return ::operator new(size);
   }
@@ -304,7 +308,7 @@
   }
 
  protected:
-  RegType(ObjPtr<mirror::Class> klass,
+  RegType(Handle<mirror::Class> klass,
           const std::string_view& descriptor,
           uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : descriptor_(descriptor),
@@ -323,7 +327,7 @@
   virtual AssignmentType GetAssignmentTypeImpl() const = 0;
 
   const std::string_view descriptor_;
-  mutable GcRoot<mirror::Class> klass_;  // Non-const only due to moving classes.
+  const Handle<mirror::Class> klass_;
   const uint16_t cache_id_;
 
   friend class RegTypeCache;
@@ -348,31 +352,16 @@
 
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Get the singleton Conflict instance.
-  static const ConflictType* GetInstance() PURE;
-
-  // Create the singleton instance.
-  static const ConflictType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                            const std::string_view& descriptor,
-                                            uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Destroy the singleton instance.
-  static void Destroy();
-
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kConflict;
   }
 
- private:
-  ConflictType(ObjPtr<mirror::Class> klass,
+  ConflictType(Handle<mirror::Class> klass,
                const std::string_view& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-
-  static const ConflictType* instance_;
 };
 
 // A variant of the bottom type used to specify an undefined value in the
@@ -384,36 +373,21 @@
 
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Get the singleton Undefined instance.
-  static const UndefinedType* GetInstance() PURE;
-
-  // Create the singleton instance.
-  static const UndefinedType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                             const std::string_view& descriptor,
-                                             uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Destroy the singleton instance.
-  static void Destroy();
-
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kNotAssignable;
   }
 
- private:
-  UndefinedType(ObjPtr<mirror::Class> klass,
+  UndefinedType(Handle<mirror::Class> klass,
                 const std::string_view& descriptor,
                 uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-
-  static const UndefinedType* instance_;
 };
 
 class PrimitiveType : public RegType {
  public:
-  PrimitiveType(ObjPtr<mirror::Class> klass,
+  PrimitiveType(Handle<mirror::Class> klass,
                 const std::string_view& descriptor,
                 uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -422,7 +396,7 @@
 
 class Cat1Type : public PrimitiveType {
  public:
-  Cat1Type(ObjPtr<mirror::Class> klass,
+  Cat1Type(Handle<mirror::Class> klass,
            const std::string_view& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -431,155 +405,107 @@
  public:
   bool IsInteger() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const IntegerType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                           const std::string_view& descriptor,
-                                           uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const IntegerType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kInteger;
   }
 
- private:
-  IntegerType(ObjPtr<mirror::Class> klass,
+  IntegerType(Handle<mirror::Class> klass,
               const std::string_view& descriptor,
               uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const IntegerType* instance_;
 };
 
 class BooleanType final : public Cat1Type {
  public:
   bool IsBoolean() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const BooleanType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                           const std::string_view& descriptor,
-                                           uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const BooleanType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kBoolean;
   }
 
- private:
-  BooleanType(ObjPtr<mirror::Class> klass,
+  BooleanType(Handle<mirror::Class> klass,
               const std::string_view& descriptor,
               uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-
-  static const BooleanType* instance_;
 };
 
 class ByteType final : public Cat1Type {
  public:
   bool IsByte() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const ByteType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                        const std::string_view& descriptor,
-                                        uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const ByteType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kByte;
   }
 
- private:
-  ByteType(ObjPtr<mirror::Class> klass,
+  ByteType(Handle<mirror::Class> klass,
            const std::string_view& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const ByteType* instance_;
 };
 
 class ShortType final : public Cat1Type {
  public:
   bool IsShort() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const ShortType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                         const std::string_view& descriptor,
-                                         uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const ShortType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kShort;
   }
 
- private:
-  ShortType(ObjPtr<mirror::Class> klass, const std::string_view& descriptor,
+  ShortType(Handle<mirror::Class> klass,
+            const std::string_view& descriptor,
             uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const ShortType* instance_;
 };
 
 class CharType final : public Cat1Type {
  public:
   bool IsChar() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const CharType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                        const std::string_view& descriptor,
-                                        uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const CharType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kChar;
   }
 
- private:
-  CharType(ObjPtr<mirror::Class> klass,
+  CharType(Handle<mirror::Class> klass,
            const std::string_view& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const CharType* instance_;
 };
 
 class FloatType final : public Cat1Type {
  public:
   bool IsFloat() const override { return true; }
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
-  static const FloatType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                         const std::string_view& descriptor,
-                                         uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const FloatType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kFloat;
   }
 
- private:
-  FloatType(ObjPtr<mirror::Class> klass,
+  FloatType(Handle<mirror::Class> klass,
             const std::string_view& descriptor,
             uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat1Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const FloatType* instance_;
 };
 
 class Cat2Type : public PrimitiveType {
  public:
-  Cat2Type(ObjPtr<mirror::Class> klass,
+  Cat2Type(Handle<mirror::Class> klass,
            const std::string_view& descriptor,
            uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_);
 };
@@ -589,50 +515,34 @@
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
   bool IsLongLo() const override { return true; }
   bool IsLong() const override { return true; }
-  static const LongLoType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                          const std::string_view& descriptor,
-                                          uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const LongLoType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kLongLo;
   }
 
- private:
-  LongLoType(ObjPtr<mirror::Class> klass,
+  LongLoType(Handle<mirror::Class> klass,
              const std::string_view& descriptor,
              uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat2Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const LongLoType* instance_;
 };
 
 class LongHiType final : public Cat2Type {
  public:
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
   bool IsLongHi() const override { return true; }
-  static const LongHiType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                          const std::string_view& descriptor,
-                                          uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const LongHiType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kNotAssignable;
   }
 
- private:
-  LongHiType(ObjPtr<mirror::Class> klass,
+  LongHiType(Handle<mirror::Class> klass,
              const std::string_view& descriptor,
              uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat2Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const LongHiType* instance_;
 };
 
 class DoubleLoType final : public Cat2Type {
@@ -640,56 +550,42 @@
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
   bool IsDoubleLo() const override { return true; }
   bool IsDouble() const override { return true; }
-  static const DoubleLoType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                            const std::string_view& descriptor,
-                                            uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const DoubleLoType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kDoubleLo;
   }
 
- private:
-  DoubleLoType(ObjPtr<mirror::Class> klass,
+  DoubleLoType(Handle<mirror::Class> klass,
                const std::string_view& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat2Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const DoubleLoType* instance_;
 };
 
 class DoubleHiType final : public Cat2Type {
  public:
   std::string Dump() const override REQUIRES_SHARED(Locks::mutator_lock_);
   bool IsDoubleHi() const override { return true; }
-  static const DoubleHiType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                            const std::string_view& descriptor,
-                                            uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static const DoubleHiType* GetInstance() PURE;
-  static void Destroy();
 
   AssignmentType GetAssignmentTypeImpl() const override {
     return AssignmentType::kNotAssignable;
   }
 
- private:
-  DoubleHiType(ObjPtr<mirror::Class> klass,
+  DoubleHiType(Handle<mirror::Class> klass,
                const std::string_view& descriptor,
                uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : Cat2Type(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-  static const DoubleHiType* instance_;
 };
 
 class ConstantType : public RegType {
  public:
-  ConstantType(uint32_t constant, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
-      : RegType(nullptr, "", cache_id), constant_(constant) {
+  ConstantType(Handle<mirror::Class> klass,
+               uint32_t constant,
+               uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
+      : RegType(klass, "", cache_id), constant_(constant) {
   }
 
 
@@ -749,9 +645,9 @@
 
 class PreciseConstType final : public ConstantType {
  public:
-  PreciseConstType(uint32_t constant, uint16_t cache_id)
+  PreciseConstType(Handle<mirror::Class> cls, uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {
+      : ConstantType(cls, constant, cache_id) {
     CheckConstructorInvariants(this);
   }
 
@@ -766,9 +662,9 @@
 
 class PreciseConstLoType final : public ConstantType {
  public:
-  PreciseConstLoType(uint32_t constant, uint16_t cache_id)
+  PreciseConstLoType(Handle<mirror::Class> cls, uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {
+      : ConstantType(cls, constant, cache_id) {
     CheckConstructorInvariants(this);
   }
   bool IsPreciseConstantLo() const override { return true; }
@@ -781,9 +677,9 @@
 
 class PreciseConstHiType final : public ConstantType {
  public:
-  PreciseConstHiType(uint32_t constant, uint16_t cache_id)
+  PreciseConstHiType(Handle<mirror::Class> cls, uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {
+      : ConstantType(cls, constant, cache_id) {
     CheckConstructorInvariants(this);
   }
   bool IsPreciseConstantHi() const override { return true; }
@@ -796,9 +692,9 @@
 
 class ImpreciseConstType final : public ConstantType {
  public:
-  ImpreciseConstType(uint32_t constat, uint16_t cache_id)
+  ImpreciseConstType(Handle<mirror::Class> cls, uint32_t constat, uint16_t cache_id)
        REQUIRES_SHARED(Locks::mutator_lock_)
-       : ConstantType(constat, cache_id) {
+       : ConstantType(cls, constat, cache_id) {
     CheckConstructorInvariants(this);
   }
   bool IsImpreciseConstant() const override { return true; }
@@ -811,9 +707,9 @@
 
 class ImpreciseConstLoType final : public ConstantType {
  public:
-  ImpreciseConstLoType(uint32_t constant, uint16_t cache_id)
+  ImpreciseConstLoType(Handle<mirror::Class> cls, uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {
+      : ConstantType(cls, constant, cache_id) {
     CheckConstructorInvariants(this);
   }
   bool IsImpreciseConstantLo() const override { return true; }
@@ -826,9 +722,9 @@
 
 class ImpreciseConstHiType final : public ConstantType {
  public:
-  ImpreciseConstHiType(uint32_t constant, uint16_t cache_id)
+  ImpreciseConstHiType(Handle<mirror::Class> cls, uint32_t constant, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : ConstantType(constant, cache_id) {
+      : ConstantType(cls, constant, cache_id) {
     CheckConstructorInvariants(this);
   }
   bool IsImpreciseConstantHi() const override { return true; }
@@ -846,17 +742,6 @@
     return true;
   }
 
-  // Get the singleton Null instance.
-  static const NullType* GetInstance() PURE;
-
-  // Create the singleton instance.
-  static const NullType* CreateInstance(ObjPtr<mirror::Class> klass,
-                                        const std::string_view& descriptor,
-                                        uint16_t cache_id)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  static void Destroy();
-
   std::string Dump() const override {
     return "null";
   }
@@ -869,14 +754,11 @@
     return true;
   }
 
- private:
-  NullType(ObjPtr<mirror::Class> klass, const std::string_view& descriptor, uint16_t cache_id)
+  NullType(Handle<mirror::Class> klass, const std::string_view& descriptor, uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
-
-  static const NullType* instance_;
 };
 
 // Common parent of all uninitialized types. Uninitialized types are created by
@@ -884,7 +766,7 @@
 // instructions and must be passed to a constructor.
 class UninitializedType : public RegType {
  public:
-  UninitializedType(ObjPtr<mirror::Class> klass,
+  UninitializedType(Handle<mirror::Class> klass,
                     const std::string_view& descriptor,
                     uint32_t allocation_pc,
                     uint16_t cache_id)
@@ -909,7 +791,7 @@
 // Similar to ReferenceType but not yet having been passed to a constructor.
 class UninitializedReferenceType final : public UninitializedType {
  public:
-  UninitializedReferenceType(ObjPtr<mirror::Class> klass,
+  UninitializedReferenceType(Handle<mirror::Class> klass,
                              const std::string_view& descriptor,
                              uint32_t allocation_pc,
                              uint16_t cache_id)
@@ -929,11 +811,12 @@
 // constructor.
 class UnresolvedUninitializedRefType final : public UninitializedType {
  public:
-  UnresolvedUninitializedRefType(const std::string_view& descriptor,
+  UnresolvedUninitializedRefType(Handle<mirror::Class> klass,
+                                 const std::string_view& descriptor,
                                  uint32_t allocation_pc,
                                  uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : UninitializedType(nullptr, descriptor, allocation_pc, cache_id) {
+      : UninitializedType(klass, descriptor, allocation_pc, cache_id) {
     CheckConstructorInvariants(this);
   }
 
@@ -951,7 +834,7 @@
 // of a constructor.
 class UninitializedThisReferenceType final : public UninitializedType {
  public:
-  UninitializedThisReferenceType(ObjPtr<mirror::Class> klass,
+  UninitializedThisReferenceType(Handle<mirror::Class> klass,
                                  const std::string_view& descriptor,
                                  uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
@@ -971,9 +854,11 @@
 
 class UnresolvedUninitializedThisRefType final : public UninitializedType {
  public:
-  UnresolvedUninitializedThisRefType(const std::string_view& descriptor, uint16_t cache_id)
+  UnresolvedUninitializedThisRefType(Handle<mirror::Class> klass,
+                                     const std::string_view& descriptor,
+                                     uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : UninitializedType(nullptr, descriptor, 0, cache_id) {
+      : UninitializedType(klass, descriptor, 0, cache_id) {
     CheckConstructorInvariants(this);
   }
 
@@ -991,7 +876,7 @@
 // sub-class.
 class ReferenceType final : public RegType {
  public:
-  ReferenceType(ObjPtr<mirror::Class> klass,
+  ReferenceType(Handle<mirror::Class> klass,
                 const std::string_view& descriptor,
                 uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_)
       : RegType(klass, descriptor, cache_id) {
@@ -1016,7 +901,7 @@
 // type.
 class PreciseReferenceType final : public RegType {
  public:
-  PreciseReferenceType(ObjPtr<mirror::Class> klass,
+  PreciseReferenceType(Handle<mirror::Class> klass,
                        const std::string_view& descriptor,
                        uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -1037,9 +922,11 @@
 // Common parent of unresolved types.
 class UnresolvedType : public RegType {
  public:
-  UnresolvedType(const std::string_view& descriptor, uint16_t cache_id)
+  UnresolvedType(Handle<mirror::Class> klass,
+                 const std::string_view& descriptor,
+                 uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : RegType(nullptr, descriptor, cache_id) {}
+      : RegType(klass, descriptor, cache_id) {}
 
   bool IsNonZeroReferenceTypes() const override;
 
@@ -1053,9 +940,11 @@
 // of this type must be conservative.
 class UnresolvedReferenceType final : public UnresolvedType {
  public:
-  UnresolvedReferenceType(const std::string_view& descriptor, uint16_t cache_id)
+  UnresolvedReferenceType(Handle<mirror::Class> cls,
+                          const std::string_view& descriptor,
+                          uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : UnresolvedType(descriptor, cache_id) {
+      : UnresolvedType(cls, descriptor, cache_id) {
     CheckConstructorInvariants(this);
   }
 
@@ -1072,10 +961,12 @@
 // Type representing the super-class of an unresolved type.
 class UnresolvedSuperClass final : public UnresolvedType {
  public:
-  UnresolvedSuperClass(uint16_t child_id, RegTypeCache* reg_type_cache,
+  UnresolvedSuperClass(Handle<mirror::Class> cls,
+                       uint16_t child_id,
+                       RegTypeCache* reg_type_cache,
                        uint16_t cache_id)
       REQUIRES_SHARED(Locks::mutator_lock_)
-      : UnresolvedType("", cache_id),
+      : UnresolvedType(cls, "", cache_id),
         unresolved_child_id_(child_id),
         reg_type_cache_(reg_type_cache) {
     CheckConstructorInvariants(this);
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index c5ff2b3..b987c2c 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -42,49 +42,49 @@
   // We only expect 0 to be a precise constant.
   DCHECK_IMPLIES(value == 0, precise);
   if (precise && (value >= kMinSmallConstant) && (value <= kMaxSmallConstant)) {
-    return *small_precise_constants_[value - kMinSmallConstant];
+    return *down_cast<const ConstantType*>(entries_[value - kMinSmallConstant]);
   }
   return FromCat1NonSmallConstant(value, precise);
 }
 
 inline const BooleanType& RegTypeCache::Boolean() {
-  return *BooleanType::GetInstance();
+  return *down_cast<const BooleanType*>(entries_[kBooleanCacheId]);
 }
 inline const ByteType& RegTypeCache::Byte() {
-  return *ByteType::GetInstance();
+  return *down_cast<const ByteType*>(entries_[kByteCacheId]);
 }
 inline const CharType& RegTypeCache::Char() {
-  return *CharType::GetInstance();
+  return *down_cast<const CharType*>(entries_[kCharCacheId]);
 }
 inline const ShortType& RegTypeCache::Short() {
-  return *ShortType::GetInstance();
+  return *down_cast<const ShortType*>(entries_[kShortCacheId]);
 }
 inline const IntegerType& RegTypeCache::Integer() {
-  return *IntegerType::GetInstance();
+  return *down_cast<const IntegerType*>(entries_[kIntCacheId]);
 }
 inline const FloatType& RegTypeCache::Float() {
-  return *FloatType::GetInstance();
+  return *down_cast<const FloatType*>(entries_[kFloatCacheId]);
 }
 inline const LongLoType& RegTypeCache::LongLo() {
-  return *LongLoType::GetInstance();
+  return *down_cast<const LongLoType*>(entries_[kLongLoCacheId]);
 }
 inline const LongHiType& RegTypeCache::LongHi() {
-  return *LongHiType::GetInstance();
+  return *down_cast<const LongHiType*>(entries_[kLongHiCacheId]);
 }
 inline const DoubleLoType& RegTypeCache::DoubleLo() {
-  return *DoubleLoType::GetInstance();
+  return *down_cast<const DoubleLoType*>(entries_[kDoubleLoCacheId]);
 }
 inline const DoubleHiType& RegTypeCache::DoubleHi() {
-  return *DoubleHiType::GetInstance();
+  return *down_cast<const DoubleHiType*>(entries_[kDoubleHiCacheId]);
 }
 inline const UndefinedType& RegTypeCache::Undefined() {
-  return *UndefinedType::GetInstance();
+  return *down_cast<const UndefinedType*>(entries_[kUndefinedCacheId]);
 }
 inline const ConflictType& RegTypeCache::Conflict() {
-  return *ConflictType::GetInstance();
+  return *down_cast<const ConflictType*>(entries_[kConflictCacheId]);
 }
 inline const NullType& RegTypeCache::Null() {
-  return *NullType::GetInstance();
+  return *down_cast<const NullType*>(entries_[kNullCacheId]);
 }
 
 inline const ImpreciseConstType& RegTypeCache::ByteConstant() {
@@ -186,9 +186,9 @@
   DCHECK(new_entry != nullptr);
   entries_.push_back(new_entry);
   if (new_entry->HasClass()) {
-    ObjPtr<mirror::Class> klass = new_entry->GetClass();
+    Handle<mirror::Class> klass = new_entry->GetClassHandle();
     DCHECK(!klass->IsPrimitive());
-    klass_entries_.push_back(std::make_pair(GcRoot<mirror::Class>(klass), new_entry));
+    klass_entries_.push_back(std::make_pair(klass, new_entry));
   }
   return *new_entry;
 }
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 0bba6e8..55b3733 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -25,6 +25,7 @@
 #include "base/scoped_arena_allocator.h"
 #include "base/stl_util.h"
 #include "class_linker-inl.h"
+#include "class_root-inl.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "mirror/class-inl.h"
@@ -34,17 +35,6 @@
 namespace art {
 namespace verifier {
 
-bool RegTypeCache::primitive_initialized_ = false;
-uint16_t RegTypeCache::primitive_count_ = 0;
-const PreciseConstType* RegTypeCache::small_precise_constants_[kMaxSmallConstant -
-                                                               kMinSmallConstant + 1];
-
-namespace {
-
-ClassLinker* gInitClassLinker = nullptr;
-
-}  // namespace
-
 ALWAYS_INLINE static inline bool MatchingPrecisionForClass(const RegType* entry, bool precise)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (entry->IsPreciseReference() == precise) {
@@ -61,32 +51,42 @@
 }
 
 void RegTypeCache::FillPrimitiveAndSmallConstantTypes() {
-  // Note: this must have the same order as CreatePrimitiveAndSmallConstantTypes.
-  entries_.push_back(UndefinedType::GetInstance());
-  entries_.push_back(ConflictType::GetInstance());
-  entries_.push_back(NullType::GetInstance());
-  entries_.push_back(BooleanType::GetInstance());
-  entries_.push_back(ByteType::GetInstance());
-  entries_.push_back(ShortType::GetInstance());
-  entries_.push_back(CharType::GetInstance());
-  entries_.push_back(IntegerType::GetInstance());
-  entries_.push_back(LongLoType::GetInstance());
-  entries_.push_back(LongHiType::GetInstance());
-  entries_.push_back(FloatType::GetInstance());
-  entries_.push_back(DoubleLoType::GetInstance());
-  entries_.push_back(DoubleHiType::GetInstance());
+  entries_.resize(kNumPrimitivesAndSmallConstants);
   for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
     int32_t i = value - kMinSmallConstant;
-    DCHECK_EQ(entries_.size(), small_precise_constants_[i]->GetId());
-    entries_.push_back(small_precise_constants_[i]);
+    entries_[i] = new (&allocator_) PreciseConstType(null_handle_, value, i);
   }
-  DCHECK_EQ(entries_.size(), primitive_count_);
+
+#define CREATE_PRIMITIVE_TYPE(type, class_root, descriptor, id) \
+  entries_[id] = new (&allocator_) type( \
+        handles_.NewHandle(GetClassRoot(class_root, class_linker_)), \
+        descriptor, \
+        id); \
+
+  CREATE_PRIMITIVE_TYPE(BooleanType, ClassRoot::kPrimitiveBoolean, "Z", kBooleanCacheId);
+  CREATE_PRIMITIVE_TYPE(ByteType, ClassRoot::kPrimitiveByte, "B", kByteCacheId);
+  CREATE_PRIMITIVE_TYPE(ShortType, ClassRoot::kPrimitiveShort, "S", kShortCacheId);
+  CREATE_PRIMITIVE_TYPE(CharType, ClassRoot::kPrimitiveChar, "C", kCharCacheId);
+  CREATE_PRIMITIVE_TYPE(IntegerType, ClassRoot::kPrimitiveInt, "I", kIntCacheId);
+  CREATE_PRIMITIVE_TYPE(LongLoType, ClassRoot::kPrimitiveLong, "J", kLongLoCacheId);
+  CREATE_PRIMITIVE_TYPE(LongHiType, ClassRoot::kPrimitiveLong, "J", kLongHiCacheId);
+  CREATE_PRIMITIVE_TYPE(FloatType, ClassRoot::kPrimitiveFloat, "F", kFloatCacheId);
+  CREATE_PRIMITIVE_TYPE(DoubleLoType, ClassRoot::kPrimitiveDouble, "D", kDoubleLoCacheId);
+  CREATE_PRIMITIVE_TYPE(DoubleHiType, ClassRoot::kPrimitiveDouble, "D", kDoubleHiCacheId);
+
+#undef CREATE_PRIMITIVE_TYPE
+
+  entries_[kUndefinedCacheId] =
+      new (&allocator_) UndefinedType(null_handle_, "", kUndefinedCacheId);
+  entries_[kConflictCacheId] =
+      new (&allocator_) ConflictType(null_handle_, "", kConflictCacheId);
+  entries_[kNullCacheId] =
+      new (&allocator_) NullType(null_handle_, "", kNullCacheId);
 }
 
 const RegType& RegTypeCache::FromDescriptor(ObjPtr<mirror::ClassLoader> loader,
                                             const char* descriptor,
                                             bool precise) {
-  DCHECK(RegTypeCache::primitive_initialized_);
   if (descriptor[1] == '\0') {
     switch (descriptor[0]) {
       case 'Z':
@@ -116,28 +116,28 @@
   }
 }
 
+
 const RegType& RegTypeCache::RegTypeFromPrimitiveType(Primitive::Type prim_type) const {
-  DCHECK(RegTypeCache::primitive_initialized_);
   switch (prim_type) {
     case Primitive::kPrimBoolean:
-      return *BooleanType::GetInstance();
+      return *entries_[kBooleanCacheId];
     case Primitive::kPrimByte:
-      return *ByteType::GetInstance();
+      return *entries_[kByteCacheId];
     case Primitive::kPrimShort:
-      return *ShortType::GetInstance();
+      return *entries_[kShortCacheId];
     case Primitive::kPrimChar:
-      return *CharType::GetInstance();
+      return *entries_[kCharCacheId];
     case Primitive::kPrimInt:
-      return *IntegerType::GetInstance();
+      return *entries_[kIntCacheId];
     case Primitive::kPrimLong:
-      return *LongLoType::GetInstance();
+      return *entries_[kLongLoCacheId];
     case Primitive::kPrimFloat:
-      return *FloatType::GetInstance();
+      return *entries_[kFloatCacheId];
     case Primitive::kPrimDouble:
-      return *DoubleLoType::GetInstance();
+      return *entries_[kDoubleLoCacheId];
     case Primitive::kPrimVoid:
     default:
-      return *ConflictType::GetInstance();
+      return *entries_[kConflictCacheId];
   }
 }
 
@@ -187,7 +187,7 @@
   std::string_view sv_descriptor(descriptor);
   // Try looking up the class in the cache first. We use a std::string_view to avoid
   // repeated strlen operations on the descriptor.
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     if (MatchDescriptor(i, sv_descriptor, precise)) {
       return *(entries_[i]);
     }
@@ -209,10 +209,13 @@
     if (klass->CannotBeAssignedFromOtherTypes() || precise) {
       DCHECK_IMPLIES(klass->IsAbstract(), klass->IsArrayClass());
       DCHECK(!klass->IsInterface());
-      entry =
-          new (&allocator_) PreciseReferenceType(klass, AddString(sv_descriptor), entries_.size());
+      entry = new (&allocator_) PreciseReferenceType(handles_.NewHandle(klass),
+                                                     AddString(sv_descriptor),
+                                                     entries_.size());
     } else {
-      entry = new (&allocator_) ReferenceType(klass, AddString(sv_descriptor), entries_.size());
+      entry = new (&allocator_) ReferenceType(handles_.NewHandle(klass),
+                                              AddString(sv_descriptor),
+                                              entries_.size());
     }
     return AddEntry(entry);
   } else {  // Class not resolved.
@@ -225,8 +228,9 @@
       DCHECK(!Thread::Current()->IsExceptionPending());
     }
     if (IsValidDescriptor(descriptor)) {
-      return AddEntry(
-          new (&allocator_) UnresolvedReferenceType(AddString(sv_descriptor), entries_.size()));
+      return AddEntry(new (&allocator_) UnresolvedReferenceType(null_handle_,
+                                                                AddString(sv_descriptor),
+                                                                entries_.size()));
     } else {
       // The descriptor is broken return the unknown type as there's nothing sensible that
       // could be done at runtime
@@ -237,7 +241,8 @@
 
 const RegType& RegTypeCache::MakeUnresolvedReference() {
   // The descriptor is intentionally invalid so nothing else will match this type.
-  return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString("a"), entries_.size()));
+  return AddEntry(new (&allocator_) UnresolvedReferenceType(
+      null_handle_, AddString("a"), entries_.size()));
 }
 
 const RegType* RegTypeCache::FindClass(ObjPtr<mirror::Class> klass, bool precise) const {
@@ -248,8 +253,8 @@
     return &RegTypeFromPrimitiveType(klass->GetPrimitiveType());
   }
   for (auto& pair : klass_entries_) {
-    const ObjPtr<mirror::Class> reg_klass = pair.first.Read();
-    if (reg_klass == klass) {
+    const Handle<mirror::Class> reg_klass = pair.first;
+    if (reg_klass.Get() == klass) {
       const RegType* reg_type = pair.second;
       if (MatchingPrecisionForClass(reg_type, precise)) {
         return reg_type;
@@ -266,8 +271,10 @@
   DCHECK(FindClass(klass, precise) == nullptr);
   RegType* const reg_type = precise
       ? static_cast<RegType*>(
-          new (&allocator_) PreciseReferenceType(klass, descriptor, entries_.size()))
-      : new (&allocator_) ReferenceType(klass, descriptor, entries_.size());
+          new (&allocator_) PreciseReferenceType(handles_.NewHandle(klass),
+                                                 descriptor,
+                                                 entries_.size()))
+      : new (&allocator_) ReferenceType(handles_.NewHandle(klass), descriptor, entries_.size());
   return &AddEntry(reg_type);
 }
 
@@ -285,13 +292,14 @@
 RegTypeCache::RegTypeCache(ClassLinker* class_linker,
                            bool can_load_classes,
                            ScopedArenaAllocator& allocator,
+                           VariableSizedHandleScope& handles,
                            bool can_suspend)
     : entries_(allocator.Adapter(kArenaAllocVerifier)),
       klass_entries_(allocator.Adapter(kArenaAllocVerifier)),
       allocator_(allocator),
+      handles_(handles),
       class_linker_(class_linker),
       can_load_classes_(can_load_classes) {
-  DCHECK_EQ(class_linker, gInitClassLinker);
   DCHECK(can_suspend || !can_load_classes) << "Cannot load classes if suspension is disabled!";
   if (kIsDebugBuild && can_suspend) {
     Thread::Current()->AssertThreadSuspensionIsAllowable(gAborting == 0);
@@ -305,92 +313,6 @@
   FillPrimitiveAndSmallConstantTypes();
 }
 
-RegTypeCache::~RegTypeCache() {
-  DCHECK_LE(primitive_count_, entries_.size());
-}
-
-void RegTypeCache::ShutDown() {
-  if (RegTypeCache::primitive_initialized_) {
-    UndefinedType::Destroy();
-    ConflictType::Destroy();
-    BooleanType::Destroy();
-    ByteType::Destroy();
-    ShortType::Destroy();
-    CharType::Destroy();
-    IntegerType::Destroy();
-    LongLoType::Destroy();
-    LongHiType::Destroy();
-    FloatType::Destroy();
-    DoubleLoType::Destroy();
-    DoubleHiType::Destroy();
-    NullType::Destroy();
-    for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
-      const PreciseConstType* type = small_precise_constants_[value - kMinSmallConstant];
-      delete type;
-      small_precise_constants_[value - kMinSmallConstant] = nullptr;
-    }
-    RegTypeCache::primitive_initialized_ = false;
-    RegTypeCache::primitive_count_ = 0;
-  }
-}
-
-// Helper for create_primitive_type_instance lambda.
-namespace {
-template <typename T>
-struct TypeHelper {
-  using type = T;
-  static_assert(std::is_convertible<T*, RegType*>::value, "T must be a RegType");
-
-  const char* descriptor;
-
-  explicit TypeHelper(const char* d) : descriptor(d) {}
-};
-}  // namespace
-
-void RegTypeCache::CreatePrimitiveAndSmallConstantTypes(ClassLinker* class_linker) {
-  gInitClassLinker = class_linker;
-
-  // Note: this must have the same order as FillPrimitiveAndSmallConstantTypes.
-
-  // It is acceptable to pass on the const char* in type to CreateInstance, as all calls below are
-  // with compile-time constants that will have global lifetime. Use of the lambda ensures this
-  // code cannot leak to other users.
-  auto create_primitive_type_instance = [&](auto type) REQUIRES_SHARED(Locks::mutator_lock_) {
-    using Type = typename decltype(type)::type;
-    ObjPtr<mirror::Class> klass = nullptr;
-    // Try loading the class from linker.
-    DCHECK(type.descriptor != nullptr);
-    if (strlen(type.descriptor) > 0) {
-      klass = class_linker->FindSystemClass(Thread::Current(), type.descriptor);
-      DCHECK(klass != nullptr);
-    }
-    const Type* entry = Type::CreateInstance(klass,
-                                             type.descriptor,
-                                             RegTypeCache::primitive_count_);
-    RegTypeCache::primitive_count_++;
-    return entry;
-  };
-  create_primitive_type_instance(TypeHelper<UndefinedType>(""));
-  create_primitive_type_instance(TypeHelper<ConflictType>(""));
-  create_primitive_type_instance(TypeHelper<NullType>(""));
-  create_primitive_type_instance(TypeHelper<BooleanType>("Z"));
-  create_primitive_type_instance(TypeHelper<ByteType>("B"));
-  create_primitive_type_instance(TypeHelper<ShortType>("S"));
-  create_primitive_type_instance(TypeHelper<CharType>("C"));
-  create_primitive_type_instance(TypeHelper<IntegerType>("I"));
-  create_primitive_type_instance(TypeHelper<LongLoType>("J"));
-  create_primitive_type_instance(TypeHelper<LongHiType>("J"));
-  create_primitive_type_instance(TypeHelper<FloatType>("F"));
-  create_primitive_type_instance(TypeHelper<DoubleLoType>("D"));
-  create_primitive_type_instance(TypeHelper<DoubleHiType>("D"));
-
-  for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
-    PreciseConstType* type = new PreciseConstType(value, primitive_count_);
-    small_precise_constants_[value - kMinSmallConstant] = type;
-    primitive_count_++;
-  }
-}
-
 const RegType& RegTypeCache::FromUnresolvedMerge(const RegType& left,
                                                  const RegType& right,
                                                  MethodVerifier* verifier) {
@@ -461,7 +383,7 @@
   }
 
   // Check if entry already exists.
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     const RegType* cur_entry = entries_[i];
     if (cur_entry->IsUnresolvedMergedReference()) {
       const UnresolvedMergedType* cmp_type = down_cast<const UnresolvedMergedType*>(cur_entry);
@@ -482,7 +404,7 @@
 
 const RegType& RegTypeCache::FromUnresolvedSuperClass(const RegType& child) {
   // Check if entry already exists.
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     const RegType* cur_entry = entries_[i];
     if (cur_entry->IsUnresolvedSuperClass()) {
       const UnresolvedSuperClass* tmp_entry =
@@ -494,14 +416,15 @@
       }
     }
   }
-  return AddEntry(new (&allocator_) UnresolvedSuperClass(child.GetId(), this, entries_.size()));
+  return AddEntry(new (&allocator_) UnresolvedSuperClass(
+      null_handle_, child.GetId(), this, entries_.size()));
 }
 
 const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32_t allocation_pc) {
   UninitializedType* entry = nullptr;
   const std::string_view& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
       const RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedReference() &&
           down_cast<const UnresolvedUninitializedRefType*>(cur_entry)->GetAllocationPc()
@@ -510,12 +433,13 @@
         return *down_cast<const UnresolvedUninitializedRefType*>(cur_entry);
       }
     }
-    entry = new (&allocator_) UnresolvedUninitializedRefType(descriptor,
+    entry = new (&allocator_) UnresolvedUninitializedRefType(null_handle_,
+                                                             descriptor,
                                                              allocation_pc,
                                                              entries_.size());
   } else {
     ObjPtr<mirror::Class> klass = type.GetClass();
-    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
       const RegType* cur_entry = entries_[i];
       if (cur_entry->IsUninitializedReference() &&
           down_cast<const UninitializedReferenceType*>(cur_entry)
@@ -524,7 +448,7 @@
         return *down_cast<const UninitializedReferenceType*>(cur_entry);
       }
     }
-    entry = new (&allocator_) UninitializedReferenceType(klass,
+    entry = new (&allocator_) UninitializedReferenceType(handles_.NewHandle(klass),
                                                          descriptor,
                                                          allocation_pc,
                                                          entries_.size());
@@ -537,25 +461,25 @@
 
   if (uninit_type.IsUnresolvedTypes()) {
     const std::string_view& descriptor(uninit_type.GetDescriptor());
-    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
       const RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedReference() &&
           cur_entry->GetDescriptor() == descriptor) {
         return *cur_entry;
       }
     }
-    entry = new (&allocator_) UnresolvedReferenceType(descriptor, entries_.size());
+    entry = new (&allocator_) UnresolvedReferenceType(null_handle_, descriptor, entries_.size());
   } else {
     ObjPtr<mirror::Class> klass = uninit_type.GetClass();
     if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) {
       // For uninitialized "this reference" look for reference types that are not precise.
-      for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
         const RegType* cur_entry = entries_[i];
         if (cur_entry->IsReference() && cur_entry->GetClass() == klass) {
           return *cur_entry;
         }
       }
-      entry = new (&allocator_) ReferenceType(klass, "", entries_.size());
+      entry = new (&allocator_) ReferenceType(handles_.NewHandle(klass), "", entries_.size());
     } else if (!klass->IsPrimitive()) {
       // We're uninitialized because of allocation, look or create a precise type as allocations
       // may only create objects of that type.
@@ -568,13 +492,13 @@
       //       2) Checking whether the klass is instantiable and using conflict may produce a hard
       //          error when the value is used, which leads to a VerifyError, which is not the
       //          correct semantics.
-      for (size_t i = primitive_count_; i < entries_.size(); i++) {
+      for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
         const RegType* cur_entry = entries_[i];
         if (cur_entry->IsPreciseReference() && cur_entry->GetClass() == klass) {
           return *cur_entry;
         }
       }
-      entry = new (&allocator_) PreciseReferenceType(klass,
+      entry = new (&allocator_) PreciseReferenceType(handles_.NewHandle(klass),
                                                      uninit_type.GetDescriptor(),
                                                      entries_.size());
     } else {
@@ -588,31 +512,34 @@
   UninitializedType* entry;
   const std::string_view& descriptor(type.GetDescriptor());
   if (type.IsUnresolvedTypes()) {
-    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
       const RegType* cur_entry = entries_[i];
       if (cur_entry->IsUnresolvedAndUninitializedThisReference() &&
           cur_entry->GetDescriptor() == descriptor) {
         return *down_cast<const UninitializedType*>(cur_entry);
       }
     }
-    entry = new (&allocator_) UnresolvedUninitializedThisRefType(descriptor, entries_.size());
+    entry = new (&allocator_) UnresolvedUninitializedThisRefType(
+        null_handle_, descriptor, entries_.size());
   } else {
     ObjPtr<mirror::Class> klass = type.GetClass();
-    for (size_t i = primitive_count_; i < entries_.size(); i++) {
+    for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
       const RegType* cur_entry = entries_[i];
       if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) {
         return *down_cast<const UninitializedType*>(cur_entry);
       }
     }
-    entry = new (&allocator_) UninitializedThisReferenceType(klass, descriptor, entries_.size());
+    entry = new (&allocator_) UninitializedThisReferenceType(handles_.NewHandle(klass),
+                                                             descriptor,
+                                                             entries_.size());
   }
   return AddEntry(entry);
 }
 
 const ConstantType& RegTypeCache::FromCat1NonSmallConstant(int32_t value, bool precise) {
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     const RegType* cur_entry = entries_[i];
-    if (cur_entry->klass_.IsNull() && cur_entry->IsConstant() &&
+    if (!cur_entry->HasClass() && cur_entry->IsConstant() &&
         cur_entry->IsPreciseConstant() == precise &&
         (down_cast<const ConstantType*>(cur_entry))->ConstantValue() == value) {
       return *down_cast<const ConstantType*>(cur_entry);
@@ -620,15 +547,15 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&allocator_) PreciseConstType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstType(null_handle_, value, entries_.size());
   } else {
-    entry = new (&allocator_) ImpreciseConstType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstType(null_handle_, value, entries_.size());
   }
   return AddEntry(entry);
 }
 
 const ConstantType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) {
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     const RegType* cur_entry = entries_[i];
     if (cur_entry->IsConstantLo() && (cur_entry->IsPrecise() == precise) &&
         (down_cast<const ConstantType*>(cur_entry))->ConstantValueLo() == value) {
@@ -637,15 +564,15 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&allocator_) PreciseConstLoType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstLoType(null_handle_, value, entries_.size());
   } else {
-    entry = new (&allocator_) ImpreciseConstLoType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstLoType(null_handle_, value, entries_.size());
   }
   return AddEntry(entry);
 }
 
 const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
-  for (size_t i = primitive_count_; i < entries_.size(); i++) {
+  for (size_t i = kNumPrimitivesAndSmallConstants; i < entries_.size(); i++) {
     const RegType* cur_entry = entries_[i];
     if (cur_entry->IsConstantHi() && (cur_entry->IsPrecise() == precise) &&
         (down_cast<const ConstantType*>(cur_entry))->ConstantValueHi() == value) {
@@ -654,9 +581,9 @@
   }
   ConstantType* entry;
   if (precise) {
-    entry = new (&allocator_) PreciseConstHiType(value, entries_.size());
+    entry = new (&allocator_) PreciseConstHiType(null_handle_, value, entries_.size());
   } else {
-    entry = new (&allocator_) ImpreciseConstHiType(value, entries_.size());
+    entry = new (&allocator_) ImpreciseConstHiType(null_handle_, value, entries_.size());
   }
   return AddEntry(entry);
 }
@@ -693,39 +620,5 @@
   }
 }
 
-void RegTypeCache::VisitStaticRoots(RootVisitor* visitor) {
-  // Visit the primitive types, this is required since if there are no active verifiers they wont
-  // be in the entries array, and therefore not visited as roots.
-  if (primitive_initialized_) {
-    RootInfo ri(kRootUnknown);
-    UndefinedType::GetInstance()->VisitRoots(visitor, ri);
-    ConflictType::GetInstance()->VisitRoots(visitor, ri);
-    BooleanType::GetInstance()->VisitRoots(visitor, ri);
-    ByteType::GetInstance()->VisitRoots(visitor, ri);
-    ShortType::GetInstance()->VisitRoots(visitor, ri);
-    CharType::GetInstance()->VisitRoots(visitor, ri);
-    IntegerType::GetInstance()->VisitRoots(visitor, ri);
-    LongLoType::GetInstance()->VisitRoots(visitor, ri);
-    LongHiType::GetInstance()->VisitRoots(visitor, ri);
-    FloatType::GetInstance()->VisitRoots(visitor, ri);
-    DoubleLoType::GetInstance()->VisitRoots(visitor, ri);
-    DoubleHiType::GetInstance()->VisitRoots(visitor, ri);
-    for (int32_t value = kMinSmallConstant; value <= kMaxSmallConstant; ++value) {
-      small_precise_constants_[value - kMinSmallConstant]->VisitRoots(visitor, ri);
-    }
-  }
-}
-
-void RegTypeCache::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
-  // Exclude the static roots that are visited by VisitStaticRoots().
-  for (size_t i = primitive_count_; i < entries_.size(); ++i) {
-    entries_[i]->VisitRoots(visitor, root_info);
-  }
-  for (auto& pair : klass_entries_) {
-    GcRoot<mirror::Class>& root = pair.first;
-    root.VisitRoot(visitor, root_info);
-  }
-}
-
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index a6d226a..d88d4db 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -26,6 +26,7 @@
 #include "base/scoped_arena_containers.h"
 #include "dex/primitive.h"
 #include "gc_root.h"
+#include "handle_scope.h"
 
 namespace art {
 
@@ -68,17 +69,8 @@
   RegTypeCache(ClassLinker* class_linker,
                bool can_load_classes,
                ScopedArenaAllocator& allocator,
+               VariableSizedHandleScope& handles,
                bool can_suspend = true);
-  ~RegTypeCache();
-  static void Init(ClassLinker* class_linker) REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (!RegTypeCache::primitive_initialized_) {
-      CHECK_EQ(RegTypeCache::primitive_count_, 0);
-      CreatePrimitiveAndSmallConstantTypes(class_linker);
-      CHECK_EQ(RegTypeCache::primitive_count_, kNumPrimitivesAndSmallConstants);
-      RegTypeCache::primitive_initialized_ = true;
-    }
-  }
-  static void ShutDown();
   const art::verifier::RegType& GetFromId(uint16_t id) const;
   const RegType& From(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -161,15 +153,32 @@
   void Dump(std::ostream& os) REQUIRES_SHARED(Locks::mutator_lock_);
   const RegType& RegTypeFromPrimitiveType(Primitive::Type) const;
 
-  void VisitRoots(RootVisitor* visitor, const RootInfo& root_info)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  static void VisitStaticRoots(RootVisitor* visitor)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   ClassLinker* GetClassLinker() {
     return class_linker_;
   }
 
+  Handle<mirror::Class> GetNullHandle() const {
+    return null_handle_;
+  }
+
+  static constexpr int32_t kMinSmallConstant = -1;
+  static constexpr int32_t kMaxSmallConstant = 4;
+  static constexpr int32_t kNumSmallConstants = kMaxSmallConstant - kMinSmallConstant + 1;
+  static constexpr size_t kNumPrimitivesAndSmallConstants = 13 + kNumSmallConstants;
+  static constexpr int32_t kBooleanCacheId = kNumSmallConstants;
+  static constexpr int32_t kByteCacheId = kNumSmallConstants + 1;
+  static constexpr int32_t kShortCacheId = kNumSmallConstants + 2;
+  static constexpr int32_t kCharCacheId = kNumSmallConstants + 3;
+  static constexpr int32_t kIntCacheId = kNumSmallConstants + 4;
+  static constexpr int32_t kLongLoCacheId = kNumSmallConstants + 5;
+  static constexpr int32_t kLongHiCacheId = kNumSmallConstants + 6;
+  static constexpr int32_t kFloatCacheId = kNumSmallConstants + 7;
+  static constexpr int32_t kDoubleLoCacheId = kNumSmallConstants + 8;
+  static constexpr int32_t kDoubleHiCacheId = kNumSmallConstants + 9;
+  static constexpr int32_t kUndefinedCacheId = kNumSmallConstants + 10;
+  static constexpr int32_t kConflictCacheId = kNumSmallConstants + 11;
+  static constexpr int32_t kNullCacheId = kNumSmallConstants + 12;
+
  private:
   void FillPrimitiveAndSmallConstantTypes() REQUIRES_SHARED(Locks::mutator_lock_);
   ObjPtr<mirror::Class> ResolveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> loader)
@@ -187,33 +196,19 @@
   // verifier and return a string view.
   std::string_view AddString(const std::string_view& str);
 
-  static void CreatePrimitiveAndSmallConstantTypes(ClassLinker* class_linker)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // A quick look up for popular small constants.
-  static constexpr int32_t kMinSmallConstant = -1;
-  static constexpr int32_t kMaxSmallConstant = 4;
-  static const PreciseConstType* small_precise_constants_[kMaxSmallConstant -
-                                                          kMinSmallConstant + 1];
-
-  static constexpr size_t kNumPrimitivesAndSmallConstants =
-      13 + (kMaxSmallConstant - kMinSmallConstant + 1);
-
-  // Have the well known global primitives been created?
-  static bool primitive_initialized_;
-
-  // Number of well known primitives that will be copied into a RegTypeCache upon construction.
-  static uint16_t primitive_count_;
-
   // The actual storage for the RegTypes.
   ScopedArenaVector<const RegType*> entries_;
 
   // Fast lookup for quickly finding entries that have a matching class.
-  ScopedArenaVector<std::pair<GcRoot<mirror::Class>, const RegType*>> klass_entries_;
+  ScopedArenaVector<std::pair<Handle<mirror::Class>, const RegType*>> klass_entries_;
 
   // Arena allocator.
   ScopedArenaAllocator& allocator_;
 
+  // Handle scope containing classes.
+  VariableSizedHandleScope& handles_;
+  ScopedNullHandle<mirror::Class> null_handle_;
+
   ClassLinker* class_linker_;
 
   // Whether or not we're allowed to load classes.
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index a36cf71..8ab7fc8 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -43,7 +43,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& ref_type_const_0 = cache.FromCat1Const(10, true);
   const RegType& ref_type_const_1 = cache.FromCat1Const(10, true);
   const RegType& ref_type_const_2 = cache.FromCat1Const(30, true);
@@ -67,7 +69,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   int64_t val = static_cast<int32_t>(1234);
   const RegType& precise_lo = cache.FromCat2ConstLo(static_cast<int32_t>(val), true);
   const RegType& precise_hi = cache.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
@@ -93,7 +97,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
 
   const RegType& bool_reg_type = cache.Boolean();
   EXPECT_FALSE(bool_reg_type.IsUndefined());
@@ -368,7 +374,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& imprecise_obj = cache.JavaLangObject(false);
   const RegType& precise_obj = cache.JavaLangObject(true);
   const RegType& precise_obj_2 = cache.FromDescriptor(nullptr, "Ljava/lang/Object;", true);
@@ -385,7 +393,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& ref_type_0 = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
   EXPECT_TRUE(ref_type_0.IsNonZeroReferenceTypes());
@@ -403,7 +413,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& ref_type_0 = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
   EXPECT_TRUE(ref_type_0.IsUnresolvedReference());
   const RegType& ref_type = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
@@ -427,7 +439,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& unresolved_ref = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExist;", true);
   const RegType& unresolved_ref_another = cache.FromDescriptor(nullptr, "Ljava/lang/DoesNotExistEither;", true);
   const RegType& resolved_ref = cache.JavaLangString();
@@ -455,7 +469,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& ref_type = cache.JavaLangString();
   const RegType& ref_type_2 = cache.JavaLangString();
   const RegType& ref_type_3 = cache.FromDescriptor(nullptr, "Ljava/lang/String;", true);
@@ -477,7 +493,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& ref_type = cache.JavaLangObject(true);
   const RegType& ref_type_2 = cache.JavaLangObject(true);
   const RegType& ref_type_3 = cache.FromDescriptor(nullptr, "Ljava/lang/Object;", true);
@@ -492,7 +510,9 @@
   ScopedObjectAccess soa(Thread::Current());
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
-  RegTypeCache cache_new(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache_new(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& string = cache_new.JavaLangString();
   const RegType& Object = cache_new.JavaLangObject(true);
   EXPECT_TRUE(string.Merge(Object, &cache_new, /* verifier= */ nullptr).IsJavaLangObject());
@@ -517,7 +537,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache_new(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache_new(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
 
   constexpr int32_t kTestConstantValue = 10;
   const RegType& float_type = cache_new.Float();
@@ -550,7 +572,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache_new(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache_new(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
 
   constexpr int32_t kTestConstantValue = 10;
   const RegType& long_lo_type = cache_new.LongLo();
@@ -610,7 +634,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache_new(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache_new(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
 
   constexpr int32_t kTestConstantValue = 10;
   const RegType& double_lo_type = cache_new.DoubleLo();
@@ -724,7 +750,9 @@
 
   ScopedDisableMovingGC no_gc(soa.Self());
 
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
 
   const RegType& conflict = cache.Conflict();
   const RegType& zero = cache.Zero();
@@ -1048,7 +1076,9 @@
   ArenaStack stack(Runtime::Current()->GetArenaPool());
   ScopedArenaAllocator allocator(&stack);
   ScopedObjectAccess soa(Thread::Current());
-  RegTypeCache cache_new(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache_new(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& imprecise_const = cache_new.FromCat1Const(10, false);
   const RegType& precise_const = cache_new.FromCat1Const(10, true);
 
@@ -1087,7 +1117,9 @@
   constexpr const char* kNumberArrayFour = "[[[[Ljava/lang/Number;";
   constexpr const char* kNumberArrayFive = "[[[[[Ljava/lang/Number;";
 
-  RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+  VariableSizedHandleScope handles(soa.Self());
+  RegTypeCache cache(
+      Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
   const RegType& int_array_array = cache.From(nullptr, kIntArrayFive, false);
   ASSERT_TRUE(int_array_array.HasClass());
   const RegType& float_array_array = cache.From(nullptr, kFloatArrayFive, false);
@@ -1127,7 +1159,9 @@
 
     ScopedDisableMovingGC no_gc(soa.Self());
 
-    RegTypeCache cache(Runtime::Current()->GetClassLinker(), true, allocator);
+    VariableSizedHandleScope handles(soa.Self());
+    RegTypeCache cache(
+        Runtime::Current()->GetClassLinker(), /* can_load_classes= */ true, allocator, handles);
     const RegType& c1_reg_type = *cache.InsertClass(in1, c1.Get(), false);
     const RegType& c2_reg_type = *cache.InsertClass(in2, c2.Get(), false);
 
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 7b5a496..6fa87c6 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -184,7 +184,7 @@
       reg_to_lock_depths_(std::less<uint32_t>(),
                           allocator.Adapter(kArenaAllocVerifier)),
       this_initialized_(false) {
-  std::uninitialized_fill_n(line_, num_regs_, 0u);
+  std::uninitialized_fill_n(line_, num_regs_, RegTypeCache::kUndefinedCacheId);
   SetResultTypeToUnknown(reg_types);
 }