Add static asserts we have a full list of mirror classes

We need to know if a particular object is of a mirrored class type in
order for structural class redefinition to work correctly. For
simplicity and to avoid making class objects larger we do this with a
simple list of mirror-class descriptors. This adds some basic
static_assert checking and a documenting macro to all mirror classes.
This should help to ensure nobody in the future unintentionally breaks
structural class redefinition by adding a new mirror type.

Test: treehugger
Bug: 144349987
Change-Id: I47c7b256655e9ce9bcf21d9670e0511bcbac65c9
diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h
index bfd0f35..7c0d91a 100644
--- a/runtime/mirror/accessible_object.h
+++ b/runtime/mirror/accessible_object.h
@@ -27,6 +27,8 @@
 // C++ mirror of java.lang.reflect.AccessibleObject
 class MANAGED AccessibleObject : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/reflect/AccessibleObject;");
+
   static MemberOffset FlagOffset() {
     return OFFSET_OF_OBJECT_MEMBER(AccessibleObject, flag_);
   }
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 4c172f2..717d1de 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -149,6 +149,15 @@
 template<typename T>
 class MANAGED PrimitiveArray : public Array {
  public:
+  MIRROR_CLASS("[Z");
+  MIRROR_CLASS("[B");
+  MIRROR_CLASS("[C");
+  MIRROR_CLASS("[S");
+  MIRROR_CLASS("[I");
+  MIRROR_CLASS("[J");
+  MIRROR_CLASS("[F");
+  MIRROR_CLASS("[D");
+
   typedef T ElementType;
 
   static ObjPtr<PrimitiveArray<T>> Alloc(Thread* self, size_t length)
diff --git a/runtime/mirror/call_site.h b/runtime/mirror/call_site.h
index ca9a9ee..88387a3 100644
--- a/runtime/mirror/call_site.h
+++ b/runtime/mirror/call_site.h
@@ -29,6 +29,8 @@
 // C++ mirror of java.lang.invoke.CallSite
 class MANAGED CallSite : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/CallSite;");
+
   ObjPtr<MethodHandle> GetTarget() REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c1593a7..3f9d41c 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -72,40 +72,9 @@
   if (IsPrimitive() || IsArrayClass() || IsProxyClass()) {
     return true;
   }
-  // TODO Have this list automatically populated.
-  std::unordered_set<std::string_view> mirror_types = {
-    "Ljava/lang/Class;",
-    "Ljava/lang/ClassLoader;",
-    "Ljava/lang/ClassNotFoundException;",
-    "Ljava/lang/DexCache;",
-    "Ljava/lang/Object;",
-    "Ljava/lang/StackTraceElement;",
-    "Ljava/lang/String;",
-    "Ljava/lang/Throwable;",
-    "Ljava/lang/invoke/ArrayElementVarHandle;",
-    "Ljava/lang/invoke/ByteArrayViewVarHandle;",
-    "Ljava/lang/invoke/ByteBufferViewVarHandle;",
-    "Ljava/lang/invoke/CallSite;",
-    "Ljava/lang/invoke/FieldVarHandle;",
-    "Ljava/lang/invoke/MethodHandle;",
-    "Ljava/lang/invoke/MethodHandleImpl;",
-    "Ljava/lang/invoke/MethodHandles$Lookup;",
-    "Ljava/lang/invoke/MethodType;",
-    "Ljava/lang/invoke/VarHandle;",
-    "Ljava/lang/ref/FinalizerReference;",
-    "Ljava/lang/ref/Reference;",
-    "Ljava/lang/reflect/AccessibleObject;",
-    "Ljava/lang/reflect/Constructor;",
-    "Ljava/lang/reflect/Executable;",
-    "Ljava/lang/reflect/Field;",
-    "Ljava/lang/reflect/Method;",
-    "Ljava/lang/reflect/Proxy;",
-    "Ldalvik/system/ClassExt;",
-    "Ldalvik/system/EmulatedStackFrame;",
-  };
   std::string name_storage;
-  const std::string name(this->GetDescriptor(&name_storage));
-  return mirror_types.find(name) != mirror_types.end();
+  const std::string_view name(this->GetDescriptor(&name_storage));
+  return IsMirroredDescriptor(name);
 }
 
 ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index fdc1be9..d29dc8c 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -81,6 +81,8 @@
 // C++ mirror of java.lang.Class
 class MANAGED Class final : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/Class;");
+
   // A magic value for reference_instance_offsets_. Ignore the bits and walk the super chain when
   // this is the value.
   // [This is an unlikely "natural" value, since it would be 30 non-ref instance fields followed by
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index fa4e87a..2fd8c39 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -33,6 +33,8 @@
 // C++ mirror of dalvik.system.ClassExt
 class MANAGED ClassExt : public Object {
  public:
+  MIRROR_CLASS("Ldalvik/system/ClassExt;");
+
   static uint32_t ClassSize(PointerSize pointer_size);
 
   // Size of an instance of dalvik.system.ClassExt.
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index c90a3da..197172c 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -35,6 +35,8 @@
 // C++ mirror of java.lang.ClassLoader
 class MANAGED ClassLoader : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/ClassLoader;");
+
   // Size of an instance of java.lang.ClassLoader.
   static constexpr uint32_t InstanceSize() {
     return sizeof(ClassLoader);
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index dd05ddd..ea52785 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -132,6 +132,8 @@
 // C++ mirror of java.lang.DexCache.
 class MANAGED DexCache final : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/DexCache;");
+
   // Size of java.lang.DexCache.class.
   static uint32_t ClassSize(PointerSize pointer_size);
 
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 626215e..b63ccaa 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -34,6 +34,8 @@
 // C++ mirror of dalvik.system.EmulatedStackFrame
 class MANAGED EmulatedStackFrame : public Object {
  public:
+  MIRROR_CLASS("Ldalvik/system/EmulatedStackFrame;");
+
   // Creates an emulated stack frame whose type is |frame_type| from
   // a shadow frame.
   static ObjPtr<mirror::EmulatedStackFrame> CreateFromShadowFrameAndArgs(
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 6f9fc0b..dc4ec95 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -32,6 +32,8 @@
 // C++ mirror of java.lang.reflect.Executable.
 class MANAGED Executable : public AccessibleObject {
  public:
+  MIRROR_CLASS("Ljava/lang/reflect/Executable;");
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
     return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 6eabd82..bbae8ce 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -39,6 +39,8 @@
 // C++ mirror of java.lang.reflect.Field.
 class MANAGED Field : public AccessibleObject {
  public:
+  MIRROR_CLASS("Ljava/lang/reflect/Field;");
+
   ALWAYS_INLINE uint32_t GetArtFieldIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, art_field_index_));
   }
diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h
index 93d61b6..4b8dcff 100644
--- a/runtime/mirror/method.h
+++ b/runtime/mirror/method.h
@@ -30,6 +30,8 @@
 // C++ mirror of java.lang.reflect.Method.
 class MANAGED Method : public Executable {
  public:
+  MIRROR_CLASS("Ljava/lang/reflect/Method;");
+
   template <PointerSize kPointerSize>
   static ObjPtr<Method> CreateFromArtMethod(Thread* self, ArtMethod* method)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
@@ -41,6 +43,8 @@
 // C++ mirror of java.lang.reflect.Constructor.
 class MANAGED Constructor: public Executable {
  public:
+  MIRROR_CLASS("Ljava/lang/reflect/Constructor;");
+
   template <PointerSize kPointerSize>
   static ObjPtr<Constructor> CreateFromArtMethod(Thread* self, ArtMethod* method)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index a0f02f6..6ba6e25 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -35,6 +35,8 @@
 // C++ mirror of java.lang.invoke.MethodHandle
 class MANAGED MethodHandle : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/MethodHandle;");
+
   // Defines the behaviour of a given method handle. The behaviour
   // of a handle of a given kind is identical to the dex bytecode behaviour
   // of the equivalent instruction.
@@ -125,6 +127,8 @@
 // C++ mirror of java.lang.invoke.MethodHandleImpl
 class MANAGED MethodHandleImpl : public MethodHandle {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/MethodHandleImpl;");
+
   static ObjPtr<mirror::MethodHandleImpl> Create(Thread* const self,
                                                  uintptr_t art_field_or_method,
                                                  MethodHandle::Kind kind,
diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h
index d4dbf83..3ed150a 100644
--- a/runtime/mirror/method_handles_lookup.h
+++ b/runtime/mirror/method_handles_lookup.h
@@ -35,6 +35,8 @@
 // C++ mirror of java.lang.invoke.MethodHandles.Lookup
 class MANAGED MethodHandlesLookup : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/MethodHandles$Lookup;");
+
   static ObjPtr<mirror::MethodHandlesLookup> Create(Thread* const self, Handle<Class> lookup_class)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
index 13edf29..872c07b 100644
--- a/runtime/mirror/method_type.h
+++ b/runtime/mirror/method_type.h
@@ -30,6 +30,8 @@
 // C++ mirror of java.lang.invoke.MethodType
 class MANAGED MethodType : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/MethodType;");
+
   static ObjPtr<MethodType> Create(Thread* const self,
                                    Handle<Class> return_type,
                                    Handle<ObjectArray<Class>> param_types)
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 2eff560..a3fc552 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -76,6 +76,8 @@
 // C++ mirror of java.lang.Object
 class MANAGED LOCKABLE Object {
  public:
+  MIRROR_CLASS("Ljava/lang/Object;");
+
   // The number of vtable entries in java.lang.Object.
   static constexpr size_t kVTableLength = 11;
 
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index e58787c..a20c86b 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -34,6 +34,8 @@
 template<class T>
 class MANAGED ObjectArray: public Array {
  public:
+  MIRROR_CLASS("[Ljava/lang/Object;");
+
   // The size of Object[].class.
   static uint32_t ClassSize(PointerSize pointer_size) {
     return Array::ClassSize(pointer_size);
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index f01bcbd..adeb29c 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -17,6 +17,9 @@
 #ifndef ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
 #define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
 
+#include <array>
+#include <string_view>
+
 #include "base/atomic.h"
 #include "base/locks.h"  // For Locks::mutator_lock_.
 #include "heap_poisoning.h"
@@ -31,6 +34,59 @@
 // Classes shared with the managed side of the world need to be packed so that they don't have
 // extra platform specific padding.
 #define MANAGED PACKED(4)
+#define MIRROR_CLASS(desc) \
+  static_assert(::art::mirror::IsMirroredDescriptor(desc), \
+                desc " is not a known mirror class. Please update" \
+                " IsMirroredDescriptor to include it!")
+
+constexpr bool IsMirroredDescriptor(std::string_view desc) {
+  if (desc[0] != 'L') {
+    // All primitives and arrays are mirrored
+    return true;
+  }
+#define MIRROR_DESCRIPTORS(vis)                       \
+    vis("Ljava/lang/Class;")                          \
+    vis("Ljava/lang/ClassLoader;")                    \
+    vis("Ljava/lang/ClassNotFoundException;")         \
+    vis("Ljava/lang/DexCache;")                       \
+    vis("Ljava/lang/Object;")                         \
+    vis("Ljava/lang/StackTraceElement;")              \
+    vis("Ljava/lang/String;")                         \
+    vis("Ljava/lang/Throwable;")                      \
+    vis("Ljava/lang/invoke/ArrayElementVarHandle;")   \
+    vis("Ljava/lang/invoke/ByteArrayViewVarHandle;")  \
+    vis("Ljava/lang/invoke/ByteBufferViewVarHandle;") \
+    vis("Ljava/lang/invoke/CallSite;")                \
+    vis("Ljava/lang/invoke/FieldVarHandle;")          \
+    vis("Ljava/lang/invoke/MethodHandle;")            \
+    vis("Ljava/lang/invoke/MethodHandleImpl;")        \
+    vis("Ljava/lang/invoke/MethodHandles$Lookup;")    \
+    vis("Ljava/lang/invoke/MethodType;")              \
+    vis("Ljava/lang/invoke/VarHandle;")               \
+    vis("Ljava/lang/ref/FinalizerReference;")         \
+    vis("Ljava/lang/ref/Reference;")                  \
+    vis("Ljava/lang/reflect/AccessibleObject;")       \
+    vis("Ljava/lang/reflect/Constructor;")            \
+    vis("Ljava/lang/reflect/Executable;")             \
+    vis("Ljava/lang/reflect/Field;")                  \
+    vis("Ljava/lang/reflect/Method;")                 \
+    vis("Ljava/lang/reflect/Proxy;")                  \
+    vis("Ldalvik/system/ClassExt;")                   \
+    vis("Ldalvik/system/EmulatedStackFrame;")
+  // TODO: Once we are C++ 20 we can just have a constexpr array and std::find.
+  // constexpr std::array<std::string_view, 28> kMirrorTypes{
+  //    // Fill in
+  // };
+  // return std::find(kMirrorTypes.begin(), kMirrorTypes.end(), desc) != kMirrorTypes.end();
+#define CHECK_DESCRIPTOR(descriptor)          \
+  if (std::string_view(descriptor) == desc) { \
+    return true;                              \
+  }
+  MIRROR_DESCRIPTORS(CHECK_DESCRIPTOR)
+#undef CHECK_DESCRIPTOR
+  return false;
+#undef MIRROR_DESCRIPTORS
+}
 
 template<bool kPoisonReferences, class MirrorType>
 class PtrCompression {
diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h
index 7775de3..3291669 100644
--- a/runtime/mirror/proxy.h
+++ b/runtime/mirror/proxy.h
@@ -28,6 +28,8 @@
 // C++ mirror of java.lang.reflect.Proxy.
 class MANAGED Proxy final : public Object {
  private:
+  MIRROR_CLASS("Ljava/lang/reflect/Proxy;");
+
   HeapReference<Object> h_;
 
   friend struct art::ProxyOffsets;  // for verifying offset information
diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h
index 9ace4f7..ef6d273 100644
--- a/runtime/mirror/reference.h
+++ b/runtime/mirror/reference.h
@@ -41,6 +41,8 @@
 // C++ mirror of java.lang.ref.Reference
 class MANAGED Reference : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/ref/Reference;");
+
   // Size of java.lang.ref.Reference.class.
   static uint32_t ClassSize(PointerSize pointer_size);
 
@@ -117,6 +119,8 @@
 // C++ mirror of java.lang.ref.FinalizerReference
 class MANAGED FinalizerReference : public Reference {
  public:
+  MIRROR_CLASS("Ljava/lang/ref/FinalizerReference;");
+
   static MemberOffset ZombieOffset() {
     return OFFSET_OF_OBJECT_MEMBER(FinalizerReference, zombie_);
   }
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 67eedbc..c07e63d 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -29,6 +29,8 @@
 // C++ mirror of java.lang.StackTraceElement
 class MANAGED StackTraceElement final : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/StackTraceElement;");
+
   ObjPtr<String> GetDeclaringClass() REQUIRES_SHARED(Locks::mutator_lock_);
 
   ObjPtr<String> GetMethodName() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 68a1c06..338a1af 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -46,6 +46,8 @@
 // C++ mirror of java.lang.String
 class MANAGED String final : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/String;");
+
   // Size of java.lang.String.class.
   static uint32_t ClassSize(PointerSize pointer_size);
 
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 68c176a..50db34c 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -31,6 +31,8 @@
 // C++ mirror of java.lang.Throwable
 class MANAGED Throwable : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/Throwable;");
+
   void SetDetailMessage(ObjPtr<String> new_detail_message) REQUIRES_SHARED(Locks::mutator_lock_);
 
   ObjPtr<String> GetDetailMessage() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 64da936..fd225e0 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -47,6 +47,8 @@
 // C++ mirror of java.lang.invoke.VarHandle
 class MANAGED VarHandle : public Object {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/VarHandle;");
+
   // The maximum number of parameters a VarHandle accessor method can
   // take. The Worst case is equivalent to a compare-and-swap
   // operation on an array element which requires four parameters
@@ -207,6 +209,8 @@
 // The corresponding managed class in libart java.lang.invoke.FieldVarHandle.
 class MANAGED FieldVarHandle : public VarHandle {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/FieldVarHandle;");
+
   bool Access(AccessMode access_mode,
               ShadowFrame* shadow_frame,
               const InstructionOperands* const operands,
@@ -250,6 +254,8 @@
 // The corresponding managed class in libart java.lang.invoke.ByteArrayViewVarHandle.
 class MANAGED ByteArrayViewVarHandle : public VarHandle {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/ByteArrayViewVarHandle;");
+
   bool Access(AccessMode access_mode,
               ShadowFrame* shadow_frame,
               const InstructionOperands* const operands,
@@ -275,6 +281,8 @@
 // The corresponding managed class in libart java.lang.invoke.ByteBufferViewVarHandle.
 class MANAGED ByteBufferViewVarHandle : public VarHandle {
  public:
+  MIRROR_CLASS("Ljava/lang/invoke/ByteBufferViewVarHandle;");
+
   bool Access(AccessMode access_mode,
               ShadowFrame* shadow_frame,
               const InstructionOperands* const operands,